MySQL 8 taking 1000x times longer to execute this query vs 5.7 when ORDER BY is used
0
votes
0
answers
925
views
This query comes from an ORM (Laravel Eloquent) on a WordPress database. I upgraded to MySQL 8 from 5.7 (AWS RDS), and the performance went from pretty speedy to basically broken. API requests that previously took ~50ms were now taking 30-60 *seconds* to execute. It was so bad I thought it was a DB connection issue at first.
I used Laravel Telescope to diagnose and one particular type of query stood out immediately (see below).
I then discovered that if I removed the
order by
, the issue went away completely! (Incidentally, if I removed the big subquery, the query was also fast).
The query:
select
*
from
wp_posts
where
post_type
= 'post'
and exists (
select
*
from
wp_term_taxonomy
inner join wp_term_relationships
on wp_term_taxonomy
.term_taxonomy_id
= wp_term_relationships
.term_taxonomy_id
where
wp_posts
.ID
= wp_term_relationships
.object_id
and taxonomy
= 'tax_channel'
and exists (
select
*
from
wp_terms
where
wp_term_taxonomy
.term_id
= wp_terms
.term_id
and slug
in ('news')
)
)
and (post_status
= 'publish')
order by wp_posts
.post_date
desc
limit 2 offset 0
**explain
results for 8.0: (takes ~30-90 seconds)**
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|----|-------------|-----------------------|------------|--------|-----------------------------------|------------------|---------|---------------------------------------------|------|----------|---------------------------------------------------------------|
| 1 | SIMPLE | wp_terms | | ref | PRIMARY,slug | slug | 766 | const | 2 | 100.00 | Using where; Using temporary; Using filesort; Start temporary |
| 1 | SIMPLE | wp_term_taxonomy | | eq_ref | PRIMARY,term_id_taxonomy,taxonomy | term_id_taxonomy | 138 | wordpress.wp_terms.term_id,const | 1 | 100.00 | Using index |
| 1 | SIMPLE | wp_term_relationships | | ref | PRIMARY,term_taxonomy_id | term_taxonomy_id | 8 | wordpress.wp_term_taxonomy.term_taxonomy_id | 238 | 100.00 | Using index |
| 1 | SIMPLE | wp_posts | | eq_ref | PRIMARY,type_status_date | PRIMARY | 8 | wordpress.wp_term_relationships.object_id | 1 | 50.00 | Using where; End temporary |
**Explain
results for 5.7 (takes ~50ms)**
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|----|--------------------|-----------------------|------------|--------|--------------------------|------------------|---------|--------------------------------------------------|--------|----------|-------------|
| 1 | PRIMARY | wp_posts | | ref | type_status_date | type_status_date | 164 | const,const | 176172 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | wp_term_relationships | | ref | PRIMARY,term_taxonomy_id | PRIMARY | 8 | wordpress.wp_posts.ID | 3 | 100.00 | Using index |
| 2 | DEPENDENT SUBQUERY | wp_term_taxonomy | | eq_ref | PRIMARY,taxonomy | PRIMARY | 8 | wordpress.wp_term_relationships.term_taxonomy_id | 1 | 5.00 | Using where |
| 3 | DEPENDENT SUBQUERY | wp_terms | | eq_ref | PRIMARY,slug | PRIMARY | 8 | wordpress.wp_term_taxonomy.term_id | 1 | 5.00 | Using where |
**Explain
results for 8.0 with order by
removed (takes ~50ms)**
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|----|-------------|-----------------------|------------|--------|-----------------------------------|------------------|---------|---------------------------------------------|------|----------|------------------------------|
| 1 | SIMPLE | wp_terms | | ref | PRIMARY,slug | slug | 766 | const | 2 | 100.00 | Using where; Start temporary |
| 1 | SIMPLE | wp_term_taxonomy | | eq_ref | PRIMARY,term_id_taxonomy,taxonomy | term_id_taxonomy | 138 | wordpress.wp_terms.term_id,const | 1 | 100.00 | Using index |
| 1 | SIMPLE | wp_term_relationships | | ref | PRIMARY,term_taxonomy_id | term_taxonomy_id | 8 | wordpress.wp_term_taxonomy.term_taxonomy_id | 238 | 100.00 | Using index |
| 1 | SIMPLE | wp_posts | | eq_ref | PRIMARY,type_status_date | PRIMARY | 8 | wordpress.wp_term_relationships.object_id | 1 | 50.00 | Using where; End temporary |
I am looking for advice on how to bring MySQL 8 performance up to the level of 5.7 with this query.
Or, a fix to the query that accomplishes the same thing. As I mentioned, this query is generated by an ORM (Eloquent) so I'm not sure how much control I have in changing the raw SQL.
Or maybe there's something I'm missing in MySQL options table?
Or, maybe I'm missing an index that could help besides the default WordPress keys?:
type_status_date BTREE FALSE post_type,post_status,post_date,ID
post_parent_id BTREE FALSE post_parent,ID
post_parent BTREE FALSE post_parent
post_name BTREE FALSE post_name(191)
post_author BTREE FALSE post_author
PRIMARY BTREE TRUE ID
**EDIT:** I've rewritten the above query as a series of JOINs instead of subqueries, but it is just as slow:
select * from wp_posts
inner join wp_term_relationships on wp_posts.ID = wp_term_relationships.object_id
inner join wp_term_taxonomy on wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
inner join wp_terms on wp_term_taxonomy.term_id = wp_terms.term_id
where post_type = 'post'
and post_status = 'publish'
and slug in ('news')
order by post_date DESC
limit 2
**EDIT 2:**
It looks like the cause of the slowness is that MySQL 8 is choosing the PRIMARY
index instead of type_status_date
. If I force it to use the latter, then the query is pretty speedy (~100ms). Still twice as high as 5.7 but at least it's in the ballpark.
Because its an ORM writing this query, I dont think this solution is viable unfortunately.
So adding /*+ index(wp_posts type_status_date) */
makes the query run in ~100ms instead of 30-90 seconds.
select /*+ index(wp_posts type_status_date) */
*
from
wp_posts
where
post_type
= 'post'
and exists (
select
*
from
wp_term_taxonomy
inner join wp_term_relationships
on wp_term_taxonomy
.term_taxonomy_id
= wp_term_relationships
.term_taxonomy_id
where
wp_posts
.ID
= wp_term_relationships
.object_id
and taxonomy
= 'tax_channel'
and exists (
select
*
from
wp_terms
where
wp_term_taxonomy
.term_id
= wp_terms
.term_id
and slug
in ('news')
)
)
and (post_status
= 'publish')
order by
wp_posts
.post_date
desc
limit
2 offset 0
Asked by Will
(1 rep)
Mar 10, 2023, 06:33 AM
Last activity: Mar 10, 2023, 06:59 PM
Last activity: Mar 10, 2023, 06:59 PM