使用ORDER BY(和索引)时痛苦的MySQL查询速度慢

时间:2014-04-18 19:19:36

标签: php mysql sql phpmyadmin

我一直在研究但无法在一个相当大的表(500k行)上解决这个缓慢的ORDER by子句。

我有以下查询:

SELECT gifts.gift_id, gifts.gift_title, gifts.gift_price, gifts.gift_image, gifts.gift_slug
FROM gifts
LEFT JOIN tags_gifts_occasion_specific AS os ON gifts.gift_id = os.gift_id
LEFT JOIN popularity ON popularity.gift_id = gifts.gift_id
WHERE published = '1'
AND (
os.tag_id IS NULL
)
ORDER BY popularity.popularity DESC , gift_id DESC

它可以快速(0.0007秒),直到添加 ORDER BY popular.popularity ,然后需要4.7秒!

流行度表确实有索引,但我知道这与排序无关。我只是不明白为什么这么慢。当我在同一张桌子中受欢迎时它速度很快,但我现在已将其移动到一个单独的表中,以提高性能和增强功能。

对此的任何建议都非常感激。

说明:

1   SIMPLE  gifts   ref     index_published     index_published     1   const   494384  Using where; Using temporary; Using filesort
1   SIMPLE  os  ref     Gift ID     Gift ID     4   gifts.gift_id   1   Using where; Using index; Not exists
1   SIMPLE  popularity  ref     Unique,Index Gift ID    Unique  4   gifts.gift_id   1   

热门表格指数:

该表有3列,所有这些列都有自己的索引(gift_id,tag_id,popular) 此搜索中未使用标记ID 三列

还有一个UNIQUE索引
Edit    Drop Drop   Unique  BTREE   Yes No  gift_id 26019   A   No  
tag_id  26019   A   No
Edit Edit   Drop Drop   Index Gift ID   BTREE   No  No  gift_id 26019   A   No  
Edit Edit   Drop Drop   Index Tag ID    BTREE   No  No  tag_id  3   A   No  
Edit Edit   Drop Drop   Index Popularity    BTREE   No  No  popularity  351 A   No  

1 个答案:

答案 0 :(得分:1)

我很好奇当您拥有索引popularity(popularity desc, gift_id)时,此版本的查询是如何执行的:

select g.gift_id, g.gift_title, g.gift_price, g.gift_image, g.gift_slug, p.popularity
from popularity p join
     gifts g
     on p.gift_id = g.gift_id
where g.published = '1' and
      not exists (select 1
                  from tags_gifts_occasion_specific tgos
                  where tgos.gift_id = p.gift_id
                 )
order by p.popularity DESC, g.gift_id DESC;

这与您的查询不完全相同,因为没有受欢迎程度的礼品不包含在结果集中。这个版本可能会说服MySQL在popularity上使用上述索引,其余的工作都是通过索引查找完成的。

编辑:

如果您愿意将其作为两个查询运行,则可以执行上述查询,然后:

select g.gift_id, g.gift_title, g.gift_price, g.gift_image, g.gift_slug
from gifts g
where g.published = '1' and
      not exists (select 1
                  from tags_gifts_occasion_specific tgos
                  where tgos.gift_id = p.gift_id
                 ) and
      not exists (select 1
                  from popularity p
                  where p.gift_id = g.gift_i
order by g.gift_id DESC;

您甚至可以将这些与union all合并。我有点气馁。它可能在实践中有效,但没有明确保证union all的结果来自第一个查询后跟第二个查询。