我有以下查询,计算每周每个区域的血管数量:
SELECT zone,
DATE_FORMAT(creation_date, '%Y%u') AS date,
COUNT(DISTINCT vessel_imo) AS vessel_count
FROM vessel_position
WHERE zone IS NOT NULL
AND creation_date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
GROUP BY zone, date;
该表有大约4000万行。执行计划是:
+----+-------------+-----------------+------------+-------+--------------------+------+---------+------+----------+----------+------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------+------------+-------+--------------------+------+---------+------+----------+----------+------------------------------------------+
| 1 | SIMPLE | vessel_position | NULL | range | creation_date,zone | zone | 5 | NULL | 21190904 | 50.00 | Using where; Using index; Using filesort |
+----+-------------+-----------------+------------+-------+--------------------+------+---------+------+----------+----------+------------------------------------------+
每个索引的vessel_imo
,zone
和creation_date
列。主键是复合键(vessel_imo
,creation_date
)。
当我查看查询配置文件时,我可以看到我花费了大量时间Creating sort index
。
我有什么办法可以进一步改进这个查询吗?
答案 0 :(得分:1)
假设数据一旦插入,就不会改变,然后构建并维护一个汇总表。
该表将有三列:区域,周,以及该周的计数。在每周开始时,仅构建 前一周的行(每个区域一行;跳过NULL
)。然后构建一个查询来对付该表 - 它将非常快,因为它将获取更少的行。
同时,INDEX(creation_date, zone, vessel_imo)
作为辅助索引,将使每周任务合理有效(约为当前查询的52倍)。
答案 1 :(得分:0)
这取决于您的过滤条件的选择程度以及您的表格结构。过滤条件是否选择20%的行,5%,1%,0.1%?
如果您的答案小于5%,则以下索引可能有所帮助:
create index ix1_date_zone on vessel_position (creation_date, zone);
如果您的表有多列和/或重列,则此选项可能仍然很慢,具体取决于您的过滤条件的选择性。
否则,您可以尝试使用更多昂贵的索引,以避免使用该表并执行:
create index ix2_date_zone_imo on vessel_position
(creation_date, zone, vessel_imo);
此索引的维护成本更高 - 阅读insert
,update
,delete
行 - 但select
会更快。
尝试这两种选择,并根据您的需求选择最佳选择。
答案 2 :(得分:0)
SET @mystartdate = DATE_SUB(CURDATE(),INTERVAL 12 MONTH);
SELECT区域,DATE_FORMAT(creation_date,'%Y%u')AS日期, COUNT(DISTINCT vessel_imo)AS vessel_count 来自vessel_position 在哪里creation_date> = @mystartdate AND区> 0 GROUP BY区域,日期;
可以在更短的时间内提供结果,请发布每次(旧的和建议的)第二次运行的比较时间
请发布新的EXPLAIN SELECT ...以确认现在使用的创建日期索引。
除非允许更改旧数据,为什么你必须收集12个月的历史记录,超过1个月前的数字不会改变。