I have a site based on WooCommerce Memberships with the Teams for WooCommerce Memberships extension. 95% of the time it copes very well despite a large user base (>70,000 users). We get about 10k daily visits with response times under one second.
There are seasonal peaks where users have to complete training and the site can crash under load of concurrent uncached requests.
Using Query Monitor there's one query which sticks out like a sore thumb: 0.0375s (average is < 0.0050s). This is a query that checks:
Is the current user a member of a TEAM with an ACTIVE subscription?
Do they have permission to view this post?
Here is the query itself:
SELECT wp_posts.*
FROM wp_posts
LEFT JOIN wp_postmeta _teams_pm
ON wp_posts.ID = _teams_pm.post_id
AND _teams_pm.meta_key = '_member_id'
AND _teams_pm.meta_value = 2
LEFT JOIN wp_usermeta _teams_um
ON _teams_um.user_id = _teams_pm.meta_value
AND _teams_um.meta_key = CONCAT( '_wc_memberships_for_teams_team_', wp_posts.ID, '_role' )
WHERE 1=1
AND ((wp_posts.post_type = 'wc_memberships_team'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'acf-disabled'
OR wp_posts.post_status = 'private')))
AND ( _teams_um.meta_value IN('manager', 'member')
OR wp_posts.post_author = 2 )
ORDER BY wp_posts.post_date DESC
It is called by:
"WP_Query->get_posts()
wp-includes/class-wp-query.php:3111
WP_Query->query()
wp-includes/class-wp-query.php:3542
WP_Query->__construct()
wp-includes/class-wp-query.php:3653
SkyVerge\W\M\T\Teams_Handler->get_teams()
wp-content/plugins/woocommerce-memberships-for-teams/src/Teams_Handler.php:446
wc_memberships_for_teams_get_teams()
wp-content/plugins/woocommerce-memberships-for-teams/src/Functions/Teams.php:100
ctz_membership_get_user_team_id()
wp-content/plugins/core-functionality/temp/wc_teams.php:603"
Does anyone have any ideas as to what indexes with MySQL could help speed this up? I'm not familiar enough with SQL to know the best place to index.
We have a big spike anticipated on Monday so I'm hoping to get something in place whilst the site is quiet this weekend.
Thanks in advance!
Edit: output of explain, with prefix and db name anonymised:
+----+-------------+---------------+------------+-------+------------------------------+------------------+---------+----------------------------------------------+------+----------+---------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+-------+------------------------------+------------------+---------+----------------------------------------------+------+----------+---------------------------------------+
| 1 | SIMPLE | wp_posts | NULL | range | type_status_date,post_author | type_status_date | 164 | NULL | 5556 | 100.00 | Using index condition; Using filesort |
| 1 | SIMPLE | _teams_pm | NULL | ref | PRIMARY,meta_key,meta_value | PRIMARY | 1030 | dbname.wp_posts.ID,const | 1 | 100.00 | Using where |
| 1 | SIMPLE | _teams_um | NULL | ref | PRIMARY,meta_key | PRIMARY | 1030 | dbname._teams_pm.meta_value,func | 1 | 100.00 | Using where |
+----+-------------+---------------+------------+-------+------------------------------+------------------+---------+----------------------------------------------+------+----------+---------------------------------------+
3 rows in set, 4 warnings (0.00 sec)