如何让这个SQL查询更快?

时间:2017-01-03 05:54:42

标签: mysql sql query-performance

我有一个包含1100000条记录的表user_notifications,我必须运行以下查询,但完成查询需要3分钟以上才能改善获取时间。

SELECT `user_notifications`.`user_id`
FROM `user_notifications`
WHERE `user_notifications`.`notification_template_id` = 175
AND (DATE(sent_at) >= DATE_SUB(CURDATE(), INTERVAL 4 day))
AND `user_notifications`.`user_id` IN (
  1203, 1282, 1499, 2244, 2575, 2697, 2828, 2900, 3085, 3989,
  5264, 5314, 5368, 5452, 5603, 6133, 6498..
)

IN块中的用户ID有时高达1k。

用于优化我已在user_id表格中的notification_template_iduser_notification列编制了索引。

enter image description here

3 个答案:

答案 0 :(得分:7)

Big IN()列表本质上很慢。创建一个带索引的临时表,并将IN()列表中的值放入该临时表中,然后您将获得索引连接的强大功能,而不是巨大的IN()列表。

答案 1 :(得分:2)

您似乎在查询小日期范围。如何根据SENT_AT列获得索引?您知道当前查询使用的索引吗?

答案 2 :(得分:1)

(1)如果您可能需要使用索引,请不要隐藏函数中的列:

AND (DATE(sent_at) >= DATE_SUB(CURDATE(), INTERVAL 4 day))

- >

AND sent_at >= CURDATE() - INTERVAL 4 day

(2)使用“复合”索引

WHERE `notification_template_id` = 175
  AND sent_at >= ...
  AND `user_id` IN (...)

第一列应为'='。目前还不清楚下一步该放什么,所以我建议添加这两个索引:

INDEX(notification_template_id, user_id, sent_at)
INDEX(notification_template_id, sent_at)

优化器可能会正确地在它们之间进行选择。

复合索引与各列上的索引相同。

(3)是的,你可以尝试将IN列表放在tmp表中,但这样做的成本可能会超过收益。我认为IN()中的1K值并不是“太多”。

(4)My cookbook关于构建索引。