我有一个包含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_id
和user_notification
列编制了索引。
答案 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关于构建索引。