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_author
That 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, 2
This SQL query behaves very badly if you have significant numbers of users – because of the
ORDER BY
clause, 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_value
in 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 BY
clause. So you would need to use theusers_pre_query
WordPress 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_orderby
public property of the passedWP_User_Query
object 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.