[wp-trac] [WordPress Trac] #55911: Slow query because Admin Bar loads all options on all user's sites
WordPress Trac
noreply at wordpress.org
Fri Jun 3 17:22:21 UTC 2022
#55911: Slow query because Admin Bar loads all options on all user's sites
------------------------------------+-----------------------------
Reporter: iandunn | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Toolbar | Version: 3.1
Severity: normal | Keywords:
Focuses: multisite, performance |
------------------------------------+-----------------------------
==== Problem
The Admin Bar displays a list of sites that the user has a role on. To get
that data, it calls `get_blogs_of_user()` when it initializes.
That's not a big deal on a single site, because everything is already
cached in memory. On Multisite, though, it can result in looping through
all of the sites that a user has a role on, and calling
`switch_to_blog()`. That calls `wp_load_alloptions()` on each site, which
can be a slow database request.
The issue gets worse the more sites the user has a role on, and the more
data stored in the `wp_options` table of those sites.
It looks like this dates back to the Admin Bar's creation in r15671.
{{{
Call Stack
# Time Memory Function Location
1 0.0001 362896 {main}( ) .../index.php:0
2 0.0001 363232 require( '/wp-blog-header.php ) .../index.php:17
3 1.8896 17408184 require_once( '/wp-includes/template-
loader.php ) .../wp-blog-header.php:19
4 1.8896 17408184 do_action( $hook_name =
'template_redirect' ) .../template-loader.php:13
5 1.8896 17408560 WP_Hook->do_action( $args = [0 => ''] )
.../plugin.php:476
6 1.8896 17408560 WP_Hook->apply_filters( $value = '', $args
= [0 => ''] ) .../class-wp-hook.php:331
7 1.8896 17409720 _wp_admin_bar_init( '' ) .../class-
wp-hook.php:307
8 1.8897 17409864 WP_Admin_Bar->initialize( ) .../admin-
bar.php:49
9 1.8897 17409904 get_blogs_of_user( $user_id = 33690, $all
= ??? ) .../class-wp-admin-bar.php:47
10 2.3312 15098272 WP_Site->__get( $key = 'blogname' )
.../user.php:994
11 2.3312 15098272 WP_Site->get_details( ) .../class-wp-
site.php:237
12 2.3312 15098272 switch_to_blog( $new_blog_id = '206',
$deprecated = ??? ) .../class-wp-site.php:323
13 2.3313 15098216 do_action( $hook_name = 'switch_blog',
...$arg = variadic('206', 1366, 'switch') ) .../ms-blogs.php:563
14 2.3313 15098592 WP_Hook->do_action( $args = [0 => '206', 1
=> 1366, 2 => 'switch'] ) .../plugin.php:476
15 2.3313 15098592 WP_Hook->apply_filters( $value = '', $args
= [0 => '206', 1 => 1366, 2 => 'switch'] ) .../class-wp-hook.php:331
16 2.3313 15098968 wp_switch_roles_and_user( $new_site_id =
'206', $old_site_id = 1366 ) .../class-wp-hook.php:309
17 2.3313 15098968 WP_Roles->for_site( $site_id = '206' )
.../ms-blogs.php:659
18 2.3313 15098968 WP_Roles->get_roles_data( ) .../class-
wp-roles.php:328
19 2.3314 15098968 get_option( $option = 'wc_206_user_roles',
$default = [] ) .../class-wp-roles.php:370
20 2.3314 15098968 wp_load_alloptions( $force_cache = ??? )
.../option.php:167
}}}
==== Potential Solution
At first glance, it seems like `wp_admin_bar_my_sites_menu()` is the only
caller (in Core), and that it only needs a few pieces of data (site name,
url, etc). Those could maybe be cached in a transient rather than doing a
`switch_to_blog()` loop on every request.
There's also some duplicated functionality between `WP_Admin_Bar` and
`wp_admin_bar_my_sites_menu()`, where the latter does a 2nd
`switch_to_blog()` loop over those same sites. That would need to be
cached too to avoid the same problem.
It may be better to refactor them so that the class isn't doing anything
on init, and instead waits for a caller to request the data, and then it
provides all the data the caller needs, to avoid the caller having to do
its own loop.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/55911>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list