优化MySQL聚合查询
-
03-07-2019 - |
题
我在 MySQL 中有一个非常大的表(约 1 亿条记录),其中包含有关文件的信息。其中一条信息是每个文件的修改日期。
我需要编写一个查询来计算符合指定日期范围的文件数量。为此,我制作了一个小表来指定这些范围(全部以天为单位),如下所示:
DateRanges
range_id range_name range_start range_end
1 0-90 0 90
2 91-180 91 180
3 181-365 181 365
4 366-1095 366 1095
5 1096+ 1096 999999999
并编写了一个如下所示的查询:
SELECT r.range_name, sum(IF((DATEDIFF(CURDATE(),t.file_last_access) > r.range_start and DATEDIFF(CURDATE(),t.file_last_access) < r.range_end),1,0)) as FileCount
FROM `DateRanges` r, `HugeFileTable` t
GROUP BY r.range_name
然而,可以预见的是,这个查询需要永远运行。我认为这是因为我要求 MySQL 遍历 HugeFileTable 5 次,每次对每个文件执行 DATEDIFF() 计算。
我想做的是仅逐条记录地遍历 HugeFileTable 记录一次,并为每个文件增加相应 range_name 运行总数中的计数。我不知道该怎么做......
有人可以帮忙解决这个问题吗?
谢谢。
编辑:MySQL 版本:5.0.45,表是MyISAM
编辑2:这是评论中要求的描述
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE r ALL NULL NULL NULL NULL 5 Using temporary; Using filesort
1 SIMPLE t ALL NULL NULL NULL NULL 96506321
解决方案
首先,在HugeFileTable.file_last_access
上创建一个索引。
然后尝试以下查询:
SELECT r.range_name, COUNT(t.file_last_access) as FileCount
FROM `DateRanges` r
JOIN `HugeFileTable` t
ON (t.file_last_access BETWEEN
CURDATE() + INTERVAL r.range_start DAY AND
CURDATE() + INTERVAL r.range_end DAY)
GROUP BY r.range_name;
这是我在MySQL 5.0.75上尝试此查询时所获得的EXPLAIN
计划(为简洁而编辑):
+-------+-------+------------------+----------------------------------------------+
| table | type | key | Extra |
+-------+-------+------------------+----------------------------------------------+
| t | index | file_last_access | Using index; Using temporary; Using filesort |
| r | ALL | NULL | Using where |
+-------+-------+------------------+----------------------------------------------+
它仍然不会表现得很好。通过使用GROUP BY
,查询会产生一个临时表,这可能很昂贵。你无能为力。
但至少此查询会删除原始查询中的笛卡尔积。
更新:这是另一个使用相关子查询的查询,但我已经删除了<=>。
SELECT r.range_name,
(SELECT COUNT(*)
FROM `HugeFileTable` t
WHERE t.file_last_access BETWEEN
CURDATE() - INTERVAL r.range_end DAY AND
CURDATE() - INTERVAL r.range_start DAY
) as FileCount
FROM `DateRanges` r;
<=>计划没有显示临时表或文件排序(至少我的测试表中有大量的行):
+----+--------------------+-------+-------+------------------+--------------------------+
| id | select_type | table | type | key | Extra |
+----+--------------------+-------+-------+------------------+--------------------------+
| 1 | PRIMARY | r | ALL | NULL | |
| 2 | DEPENDENT SUBQUERY | t | index | file_last_access | Using where; Using index |
+----+--------------------+-------+-------+------------------+--------------------------+
在您的数据集上尝试此查询,看看它是否表现更好。
其他提示
首先,请确保file_last_access
是表格HugeFileTable
的索引。
我不确定这是否可行\更好,但首先尝试计算日期限制(文件从日期 A 到日期 B ),然后使用一些查询<!> gt; =和<!> lt; =。从理论上讲,它至少会改善性能。
比较如下:
t.file_last_access >= StartDate AND t.file_last_access <= EndDate
您可以通过删除 CURDATE() 并在查询中添加日期来获得一个小改进,因为它将在 SQL 中为每行运行此函数两次。