Making WordPress.org

Changeset 11547


Ignore:
Timestamp:
02/11/2022 02:41:09 AM (2 years ago)
Author:
dd32
Message:

Support Forums: Optimize wp-admin/users.php queries a bit.

This page is always going to be slow, but there's certain optimizations we can do to speed things up.

Searching for users will still take 20+ seconds, but the page will load, rather than timing out.

See [10638] for prior art.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/support-forums/inc/class-performance-optimizations.php

    r11319 r11547  
    6262        // Add some caching on count_users().
    6363        add_filter( 'pre_count_users', array( $this, 'cache_count_users' ), 10, 3 );
     64        // ..and don't do expensive orderbys & counting for user queries that don't need it.
     65        add_action( 'pre_get_users', array( $this, 'pre_get_users' ) );
    6466    }
    6567
     
    562564     *
    563565     * This slows wp-admin/users.php down so much that it's hard to use when required.
    564      * As these numbers don't change often, it's cached for 6 hours, which avoids a 20-60s query on each users.php pageload.
     566     * As these numbers don't change often, it's cached for 24hrs hours, which avoids a 20-60s query on each users.php pageload.
    565567     */
    566568    public function cache_count_users( $result, $strategy, $site_id ) {
     569        global $wpdb;
    567570        static $running = false;
    568571
     
    573576        switch_to_blog( $site_id );
    574577
    575         $result = get_site_transient( 'count_users' );
     578        $result = get_transient( 'count_users' );
    576579        if ( ! $result ) {
     580            if ( is_callable( [ $wpdb, 'send_reads_to_masters' ] ) ) {
     581                $wpdb->send_reads_to_masters(); // unfortunate.
     582            }
     583
     584            // always time strategy, memory loads every single meta_value, that ain't gonna work.
     585            $strategy = 'time';
     586
    577587            $running = true;
    578588            $result  = count_users( $strategy, $site_id );
    579589            $running = false;
    580590
    581             set_site_transient( 'count_users', $result, 6 * HOUR_IN_SECONDS );
     591            set_transient( 'count_users', $result, DAY_IN_SECONDS );
    582592        }
    583593
     
    586596        return $result;
    587597    }
     598
     599    /**
     600     * Filter use queries to be more performant, as the default WordPress user queries
     601     * just don't scale to several million users here.
     602     *
     603     * @param \WP_User_Query $query
     604     */
     605    public function pre_get_users( $query ) {
     606        $is_role_related = false;
     607        foreach ( [ 'role', 'role__in', 'role__not_in', 'capability', 'capability__in', 'capability__not_in' ] as $var ) {
     608            if ( ! empty( $query->query_vars[ $var ] ) ) {
     609                $is_role_related = true;
     610                break;
     611            }
     612        }
     613
     614        // Don't count users unless searching.
     615        if ( empty( $query->query_vars['search'] ) && ! $is_role_related ) {
     616            $query->query_vars['count_total'] = false;
     617        }
     618
     619        // Sort by ID instead of login by default, speeds up initial load.
     620        if ( 'login' === $query->query_vars['orderby'] && empty( $_GET['orderby'] ) ) {
     621            $query->query_vars['orderby'] = 'ID';
     622            $query->query_vars['order'] = 'DESC';
     623        }
     624
     625        // Searches for email domains should be wildcard before only.
     626        if ( str_starts_with( $query->query_vars['search'], '*@' ) && str_ends_with( $query->query_vars['search'], '*' ) ) {
     627            $is_role_related = false;
     628
     629            $query->query_vars['search'] = '*' . trim( $query->query_vars['search'], '*' );
     630        }
     631
     632        // If a search is being performed, and it's not capability/role dependant, ignore the blog_id.
     633        if ( $query->query_vars['blog_id'] && ! $is_role_related ) {
     634            $query->query_vars['blog_id'] = false;
     635        }
     636    }
    588637}
Note: See TracChangeset for help on using the changeset viewer.