MYSQL 分组依据和位置索引,带有时间戳列



我已经实现了这个查询:

SELECT 
evt.userId, evt.storeId, COUNT(1) AS totalVisits
FROM
Event evt
WHERE
evt.timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW()
AND 
evt.subtype = 2 
AND 
userID IS NOT NULL
GROUP BY userId, storeId
HAVING totalVisits>16;

事件表有数百万条记录。列时间戳为 DATETIME,其他列为 INT。此表经常被访问,并且具有大量索引。

一开始,此查询需要 10 多分钟才能执行。我通过添加新索引来解决这个问题

ALTER TABLE Event 
ADD INDEX `Event_timestamp_subtype_userId_storeId` (`timestamp` ASC, `subType` ASC, `userId` ASC, `storeId` ASC);

这工作正常,我在不到 2 秒的时间内就有结果。

我遇到的问题是当我更改条件时 间隔 30 天。如果我设置间隔 50 天(例如(,MYSQL 不会使用我创建的索引。相反,它使用另一个仅涵盖两列的索引。

解释命令:

EXPLAIN EXTENDED SELECT 
evt.userId, evt.storeId, COUNT(1) AS totalVisits
FROM
Event evt
WHERE
evt.timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 50 DAY) AND NOW()
AND 
evt.subtype = 2 
AND 
evt.userID IS NOT NULL
GROUP BY userId, storeId
HAVING totalVisits>16;

解释输出:

+----+-------------+-------+------------+------+------------------------------------------------------------------------------------------------------------+-----------------------------+---------+-------+---------+----------+---------------------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys                                                                                              | key                         | key_len | ref   | rows    | filtered | Extra                                                               |
+----+-------------+-------+------------+------+------------------------------------------------------------------------------------------------------------+-----------------------------+---------+-------+---------+----------+---------------------------------------------------------------------+
|  1 | SIMPLE      | evt   | NULL       | ref  | Event_userId_index,Event_subType_storeId_index,Event_timetamp_index,Event_timestamp_subtype_userId_storeId | Event_subType_storeId_index | 3       | const | 7375964 |    25.00 | Using index condition; Using where; Using temporary; Using filesort |
+----+-------------+-------+------------+------+------------------------------------------------------------------------------------------------------------+-----------------------------+---------+-------+---------+----------+---------------------------------------------------------------------+

因此,如果放置 50 天条件,则查询不可行。如何使此查询独立于参数值使用正确的索引?

我正在使用 mysql 服务器 5.7.23

谢谢!

问候

你有"很多索引"。 霰弹枪无济于事。 您是否有这些索引,列按给定顺序排列

INDEX(subtype, timestamp)
INDEX(subtype, userID)

优化程序可能希望将其中任何一个用于WHERE。 而且,由于它不能消耗所有WHERE(因为 2 个范围(,因此它不会到达GROUP BY中的列。

第一列(subtype(用=测试;这很容易。
第二列是"范围",所以这是它可以处理的最后一件事。

通过将每个索引变成一个"覆盖"索引,可以得到一个小的改进:

INDEX(subtype, timestamp, storeID, userID)
INDEX(subtype, userID, timestamp, storeID)

现在,处理只需要查看索引的 BTree,而不必在该 BTree 和包含数据的 BTree 之间跳动。

(前 2 列按特定顺序排列;其他两列可以交换。

如果这是一个"巨大"的表(数百万行(,我们可以讨论另一种优化,因为您实际上需要一个 2D 索引。

最新更新