Very inefficient SQL query
-
On every page of the admin area, this stack of calls is made:
require_once('wp-admin/admin-header.php'), do_action('admin_enqueue_scripts'), WP_Hook->do_action, WP_Hook->apply_filters, Nelio_Content_Admin->register_assets, Nelio_Content_Admin->is_multi_authorThat method makes a call to
get_users()which generates an SQL query like this (the exact contents will depend on which roles on your site have the “edit posts” capability:SELECT wp_users.* FROM wp_users INNER JOIN wp_usermeta ON ( wp_users.ID = wp_usermeta.user_id ) WHERE 1=1 AND ( ( ( ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"edit\\_posts\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"administrator\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"author\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"contributor\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"editor\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"shop\\_manager\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"wpseo\\_manager\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"wpseo\\_editor\"%' ) ) ) ) ORDER BY user_login ASC LIMIT 0, 2This SQL query behaves very badly if you have significant numbers of users – because of the
ORDER BYclause, it searches through *all* the meta values for all of those keys for all users in order to be able to apply the ordering; even though the caller doesn’t care at all about the order – it only wants to know “was there more than one result?”. Sincemeta_valuein WordPress is not indexed, it results in a full row scan of all the results.On the site I am examining this on, which has over 250,000 users, this query generally takes about 5 seconds.
i.e. Every page in the admin area suffers that delay because of that SQL query.
Unfortunately
get_users()does not allow you to make a query without anORDER BYclause. So you would need to use theusers_pre_queryWordPress filter to simply remove that clause from the query before it is executed.i.e. Hook that filter in the method above, setting the
query_orderbypublic property of the passedWP_User_Queryobject to the empty string. (Then unhook the filter after callingget_users()so that it doesn’t affect any other parts of WordPress). This will make the query execute very quickly, because it will then no longer need to row scan the meta value for every user on the site.
The topic ‘Very inefficient SQL query’ is closed to new replies.