当用于限制id范围的附加子查询的结果比WHERE中相同查询的结果快10倍时,会遇到奇怪的情况。
此查询大约需要10秒:
SELECT COUNT(DISTINCT i.id) AS count FROM
items i
INNER JOIN items_keywords ik ON ik.article_id = i.id AND ik.deleted = 0
INNER JOIN category_keywords catk ON catk.keyword_id = ik.keyword_id
INNER JOIN category cat ON cat.id = catk.category_id AND cat.customer_id = 968
WHERE
i.deleted = 0
AND i.edited = 1
AND i.created >= '2018-12-18'
AND i.created <= '2018-12-20 23:59:59'
说明:
如果我添加其他where子句来设置最小ID,则最多需要1秒钟:
AND i.id > (SELECT MIN(id) FROM items WHERE created >= '2018-12-01')
说明:
使用子查询设置i.id范围(在主查询中删除了i。,并且没有最小id子句)对它进行了测试,它花费了10秒钟,并且解释与第一个查询相同,除了子查询行和主查询中没有创建的索引
AND i.id IN (SELECT id FROM items WHERE created >= '2018-12-18' AND created <= '2018-12-20 23:59:59') #subquery takes 0,047s
所以我应该更改索引中的某些内容还是将最小ID子查询添加到我的所有查询中,因为这会大大提高? 等待任何建议。
某些规格:
的MySQL:5.6.4
项目表:2200万行
items_keywords:1.2亿行
category_keywords:7000万行
这是我的第一个问题,所以不要怪我,而要教我。
答案 0 :(得分:0)
快10倍-听起来就像在buffer_pool中缓存的数据和没有缓存的数据之间的差异。您为每个查询两次吗?
请为每个表格提供SHOW CREATE TABLE
;可能会发生很多微妙的事情。
此索引可能会诱使它首先使用:
INDEX(deleted, edited, -- in either order
created, -- after those others
id) -- last
该索引正在“覆盖”,从而提供了额外的推动力。
当前,优化程序决定从cat.customer_id = 968
开始。
如果category_keywords
是一个多对多映射表,请参见this以获取一些性能提示。
IN ( SELECT ... )
可能会过慢。 EXISTS ( SELECT ... )
可能会更快。
如果要将内容移入子查询,请将所有i.
测试移入其中。这样,它本质上将类似于EXISTS
,并且可以使用PRIMARY KEY(id)
作为完美索引。 (不需要额外的索引。)