我怎样才能使这个 sql 查询更快?
How can I make this sql query faster?
我有一个 table user_notifications,它有 1100000 条记录,我必须 运行 下面的查询,但完成查询需要 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_notification
table.
中的 user_id
和 notification_template_id
列建立了索引
您查询的日期范围似乎很小。有一个基于 SENT_AT 列的索引怎么样?您知道当前查询使用的是什么索引吗?
大 IN() 列表本质上很慢。创建一个带有索引的临时 table 并将 IN() 列表中的值放入该临时 table 中,然后您将获得索引连接的强大功能,而不是巨大的 IN() 列表。
(1) 如果您可能需要使用索引,请不要在函数中隐藏列:
AND (DATE(sent_at) >= DATE_SUB(CURDATE(), INTERVAL 4 day))
-->
AND sent_at >= CURDATE() - INTERVAL 4 day
(2) 使用 "composite" 索引
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 table,但这样做的成本可能超过收益。我不认为 IN()
中的 1K 值是 "too many"。
(4) My cookbook 关于建立索引。
我有一个 table user_notifications,它有 1100000 条记录,我必须 运行 下面的查询,但完成查询需要 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_notification
table.
user_id
和 notification_template_id
列建立了索引
您查询的日期范围似乎很小。有一个基于 SENT_AT 列的索引怎么样?您知道当前查询使用的是什么索引吗?
大 IN() 列表本质上很慢。创建一个带有索引的临时 table 并将 IN() 列表中的值放入该临时 table 中,然后您将获得索引连接的强大功能,而不是巨大的 IN() 列表。
(1) 如果您可能需要使用索引,请不要在函数中隐藏列:
AND (DATE(sent_at) >= DATE_SUB(CURDATE(), INTERVAL 4 day))
-->
AND sent_at >= CURDATE() - INTERVAL 4 day
(2) 使用 "composite" 索引
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 table,但这样做的成本可能超过收益。我不认为 IN()
中的 1K 值是 "too many"。
(4) My cookbook 关于建立索引。