首先,对不起,如果使用的条款不对。我不是mySQL专业人士。
我有一张这样的表:
CREATE TABLE `accesses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` int(11) DEFAULT NULL,
`accessed_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_accesses_on_accessed_at` (`accessed_at`)
) ENGINE=InnoDB AUTO_INCREMENT=9278483 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
此表格中包含 10.000.000 行。我用它来生成图表,查询如下:
SELECT SUM(time) AS value, DATE(created_at) AS date
FROM `accesses`
GROUP BY date;
此查询非常长(超过1分钟)。我做了很多其他查询(AVG
,MIN
或MAX
代替SUM
,或在特定日期使用WHERE
或月,或GROUP BY HOUR(created_at)
等等......)
我想优化它。
我最好的想法是添加多个具有冗余的列,例如DATE(created_at)
,HOUR(created_at)
,MONTH(created_at)
,然后在其上添加索引。
......这个解决方案是好还是还有其他解决方案?
此致
答案 0 :(得分:2)
是的,可以优化将数据冗余地存储在永久列中,并使用索引来优化某些查询。这是非规范化的一个例子。
根据数据量和查询频率,这可能是一个重要的加速(@Marshall Tigerus过分夸大,恕我直言)。
我通过运行EXPLAIN测试了这个:
mysql> explain SELECT SUM(time) AS value, DATE(created_at) AS date FROM `accesses` GROUP BY date\G *************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: accesses
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using temporary; Using filesort
忽略我的测试中表格为空的事实。重要的部分是Using temporary; Using filesort
这是昂贵的操作,特别是如果你的临时表变得如此之大以至于MySQL无法在内存中使用它。
我在它们上添加了一些列和索引:
mysql> alter table accesses add column cdate date, add key (cdate),
add column chour tinyint, add key (chour),
add column cmonth tinyint, add key (cmonth);
mysql> explain SELECT SUM(time) AS value, cdate FROM `accesses` GROUP BY cdate\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: accesses
partitions: NULL
type: index
possible_keys: cdate
key: cdate
key_len: 4
ref: NULL
rows: 1
filtered: 100.00
Extra: NULL
临时表和filesort消失了,因为MySQL知道它可以进行索引扫描以正确的顺序处理行。