[wp-trac] [WordPress Trac] #61025: Do not write in DB when updating a user if no user data has changed

WordPress Trac noreply at wordpress.org
Wed Apr 17 15:32:34 UTC 2024


#61025: Do not write in DB when updating a user if no user data has changed
-------------------------+-----------------------------
 Reporter:  asumaran     |      Owner:  (none)
     Type:  enhancement  |     Status:  new
 Priority:  normal       |  Milestone:  Awaiting Review
Component:  Users        |    Version:  6.5
 Severity:  normal       |   Keywords:
  Focuses:  performance  |
-------------------------+-----------------------------
 I've been working on improving the response times when checking out using
 WooCommerce.

 We use Hyper DB with a separate host for writes. Subsequent reads are
 affected after every write. Avoiding any write query helps.

 I noticed there's a duplicate query when checking out.

 {{{
 #!sql
 UPDATE `wp_users` SET `user_pass` = '$P$BlixIWEMbCbx76WhYlGoBnta7X8Bgf.',
 `user_nicename` = 'foo1713310736', `user_email` =
 'foo1713310736 at mail.test', `user_url` = '', `user_registered` =
 '2024-04-16 23:38:56', `user_activation_key` = '', `display_name` =
 'foo1713310736' WHERE `ID` = 180
 }}}

 Turns out, WC creates a new cutomer using `wc_create_new_customer`
 [https://github.com/woocommerce/woocommerce/blob/ec80c8d641c9636f610cbcc4124c7600712bcf50/plugins/woocommerce/includes
 /data-stores/class-wc-customer-data-store.php#L112C9-L112C31 which] under
 the good
 [https://github.com/woocommerce/woocommerce/blob/ec80c8d641c9636f610cbcc4124c7600712bcf50/plugins/woocommerce/includes
 /wc-user-functions.php#L109 uses] `wp_insert_user` and then lines
 [https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/includes
 /class-wc-checkout.php#L1154 below]
 [https://github.com/woocommerce/woocommerce/blob/ec80c8d641c9636f610cbcc4124c7600712bcf50/plugins/woocommerce/includes
 /class-wc-checkout.php#L1187 updates] the customer using
 `WC_Customer->save()` method which under the hood uses `wp_update_user`
 which also uses `wp_insert_user`.


 At first I've tried to fix it in WooCommerce's scope but the issue is in
 the `wp_insert_user` function.

 Since there's no hook to control the write, I'm proposing the same as
 `update_metadata` is
 [https://github.com/WordPress/WordPress/blob/6fe9681e77813d4543918eeafc735fb0c4fba250
 /wp-includes/meta.php#L244-L246 already doing], if the passed value is the
 same as the previous one then skip the write query.


 Here's how to reproduce the improvement:

 Run the following using WP Shell

 {{{
 #!php
 $username = 'foo' . time();
 $user_email = $username . '@mail.test';
 $user_id = wp_insert_user([ 'user_login' => $username, 'user_pass' =>
 'password', 'user_email' => $user_email ]);
 wp_update_user( [ 'ID' => $user_id, 'user_email' => $user_email ] );
 wp_update_user( [ 'ID' => $user_id, 'user_email' => $user_email ] );
 wp_update_user( [ 'ID' => $user_id, 'user_email' => $user_email ] );
 exit;
 }}}

 Small plugin to inspect queries
 {{{
 #!php
 <?php
 /*
  * Plugin Name: Show Queries (@asumaran)
  */

 if ( ! defined( 'SAVEQUERIES' ) ) {
         define( 'SAVEQUERIES', true );
 }

 add_action( 'shutdown', 'output_queries' );

 function output_queries() {
         global $wpdb;
         $queries = [];
         foreach ( $wpdb->queries as $query ) {
                 if ( str_contains( $query[0], 'UPDATE `wp_users`' ) ) {
                         $queries[] = $query[0];
                 }
         }
         error_log( "\r\n" . print_r( join( "\r\n", $queries ), true ) );
 }
 }}}

 Without the patch:

 It should show 3 `UPDATE` to the `wp_users` table in the log

 {{{
 #!sql
 UPDATE `wp_users` SET `user_pass` = '$P$BlDtStXHL/XErbE2J8VeILcjNOcVub.',
 `user_nicename` = 'foo1713365151', `user_email` =
 'foo1713365151 at mail.test', `user_url` = '', `user_registered` =
 '2024-04-17 14:45:51', `user_activation_key` = '', `display_name` =
 'foo1713365151' WHERE `ID` = 183
 UPDATE `wp_users` SET `user_pass` = '$P$BlDtStXHL/XErbE2J8VeILcjNOcVub.',
 `user_nicename` = 'foo1713365151', `user_email` =
 'foo1713365151 at mail.test', `user_url` = '', `user_registered` =
 '2024-04-17 14:45:51', `user_activation_key` = '', `display_name` =
 'foo1713365151' WHERE `ID` = 183
 UPDATE `wp_users` SET `user_pass` = '$P$BlDtStXHL/XErbE2J8VeILcjNOcVub.',
 `user_nicename` = 'foo1713365151', `user_email` =
 'foo1713365151 at mail.test', `user_url` = '', `user_registered` =
 '2024-04-17 14:45:51', `user_activation_key` = '', `display_name` =
 'foo1713365151' WHERE `ID` = 183
 }}}

 With the patch:

 It shouldn't log any update queries to the `wp_users` table.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/61025>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list