我有一个关键字表,我定期根据远程搜索 API 刷新该表,并且我还有另一个表,每次刷新其中一个关键字时,该表都会获取一行。我使用此表来阻止多个进程相互干扰并刷新相同的关键字以及统计信息收集。因此,当我启动程序时,它会查询当前没有处理请求的所有关键字,并且在过去 15 分钟内或任何时间间隔内没有成功的请求。有一段时间一切都工作正常,但现在 keywords_requests 表中有近 200 万行,事情严重陷入困境。我在 keywords_requests 表中的几乎每一列上都有索引,但无济于事。
我正在记录缓慢的查询,而这个查询花费了很长时间,如您所见。我能做什么?
# Query_time: 20 Lock_time: 0 Rows_sent: 568 Rows_examined: 1826718 SELECT Keyword.id, Keyword.keyword FROM `keywords` as Keyword LEFT JOIN `keywords_requests` as KeywordsRequest ON ( KeywordsRequest.keyword_id = Keyword.id AND (KeywordsRequest.status = 'success' OR KeywordsRequest.status = 'active') AND KeywordsRequest.source_id = '29' AND KeywordsRequest.created > FROM_UNIXTIME(1234551323) ) WHERE KeywordsRequest.id IS NULL GROUP BY Keyword.id ORDER BY KeywordsRequest.created ASC;
最佳答案
看来您对 Keywords
最具选择性的索引是 KeywordRequest.created
上的索引。
尝试以这种方式重写查询:
SELECT Keyword.id, Keyword.keyword
FROM `keywords` as Keyword
LEFT OUTER JOIN (
SELECT *
FROM `keywords_requests` as kr
WHERE created > FROM_UNIXTIME(1234567890) /* Happy unix_time! */
) AS KeywordsRequest
ON (
KeywordsRequest.keyword_id = Keyword.id
AND (KeywordsRequest.status = 'success' OR KeywordsRequest.status = 'active')
AND KeywordsRequest.source_id = '29'
)
WHERE keyword_id IS NULL;
它将(希望)散列连接两个不太大的源。
Bill Karwin 是对的,您不需要 GROUP BY
或 ORDER BY
MySQL 中的计划无法精细控制,但您可以尝试(尝试)通过以下方式改进您的查询:
在
(keyword_id、status、source_id、created)上创建复合索引
并使其如下:SELECT Keyword.id, Keyword.keyword FROM `keywords` as Keyword LEFT OUTER JOIN `keywords_requests` kr ON ( keyword_id = id AND status = 'success' AND source_id = '29' AND created > FROM_UNIXTIME(1234567890) ) WHERE keyword_id IS NULL UNION SELECT Keyword.id, Keyword.keyword FROM `keywords` as Keyword LEFT OUTER JOIN `keywords_requests` kr ON ( keyword_id = id AND status = 'active' AND source_id = '29' AND created > FROM_UNIXTIME(1234567890) ) WHERE keyword_id IS NULL
理想情况下,应该在索引上使用
NESTED LOOPS
。在
(status、source_id、created)上创建复合索引
并使其如下:SELECT Keyword.id, Keyword.keyword FROM `keywords` as Keyword LEFT OUTER JOIN ( SELECT * FROM `keywords_requests` kr WHERE status = 'success' AND source_id = '29' AND created > FROM_UNIXTIME(1234567890) UNION ALL SELECT * FROM `keywords_requests` kr WHERE status = 'active' AND source_id = '29' AND created > FROM_UNIXTIME(1234567890) ) ON keyword_id = id WHERE keyword_id IS NULL
这有望在更受限制的哈希表上使用
HASH JOIN
。
关于mysql - 如何优化查找不存在条件联接行的行的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/547552/