CREATE TABLE `p` (
`id` bigint(20) unsigned NOT NULL,
`rtime` datetime NOT NULL,
`d` int(10) NOT NULL,
`n` int(10) NOT NULL,
PRIMARY KEY (`rtime`,`id`,`d`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
我有一个问题:
select id, d, sum(n) from p where rtime between '2012-08-25' and date(now()) group by id, d;
我在一张小桌子上运行这个查询的解释(2条记录),它告诉我它将使用我的PK:
id | select_type | table | type | possible_keys key | key | key_len | ref | rows | Extra
1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 1 | Using where; Using temporary; Using filesort
但是当我在同一张桌子上使用相同的查询时 - 只有这次它是巨大的(3.5亿条记录) - 它更喜欢浏览所有记录并忽略我的密钥
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | SIMPLE | p | ALL | PRIMARY | NULL | NULL | NULL | 355465280 | Using where; Using temporary; Using filesort
显然,这非常慢..
有人可以帮忙吗?
编辑:这个简单的查询也花了很多时间:
select count(*) from propagation_delay where rtime > '2012-08-28';
答案 0 :(得分:1)
您的查询:
...WHERE rtime between '2012-08-25' and date(now()) group by id, d;
使用rtime,按ID和d分组。至少你应该按rtime
索引。您可能还想尝试按此顺序按rtime, id, d, n
进行索引,但是当您这样做时,您会看到您的索引将包含与您的表格大致相同的数据。
可能,优化器会进行一些计算,并得出结论:使用索引并不值得。
我只在rtime
留下一个索引。真正的关键是有多少记录与WHERE
匹配 - 如果它们只是少数记录,那么读取索引并在表格中跳转是很方便的。如果他们是几个,也许最好顺序扫描整个表格,节省往返阅读。
这个查询在350万美元中占了很大比重 - 我会说几百万
好吧,那么从索引中快速提取半打记录的累积成本很可能,然后从主表往返来恢复那半打的记录,超过了打开的成本主表,拖曳所有350M记录分组和总结。
在这种情况下, if 你总是(或大部分)在rtime
上运行聚合查询,并且该表是一个累积(历史)表,并且每对{{1}每天看到几十个条目,你可以考虑创建一个按日期聚合二级表。即,在(比如)午夜,您运行查询并
(id, d)
INSERT INTO aggregate_table
SELECT DATE(@yesterday) AS rtime, id, d, sum(n) AS n
FROM main_table WHERE DATE(rtime) = @yesterday GROUP BY id, d;
中的数据只有每一对aggregate_table
只有(id, d)
当天的一个条目;表格按比例缩小,查询速度更快。这假设您的n
数量相对较少,并且每个都会在主表中每天生成大量行。
每对夫妇每分钟记录一次,聚合应该可以将事物加速超过三个数量级(相反,如果你每天两次使用大量不同的传感器,那么效益可以忽略不计)。 / p>
答案 1 :(得分:1)
在你的第二个查询中,日期范围将返回MySQL决定不使用索引的那么多行。这样做是因为n
未包含在索引中。非覆盖索引仍然是查找,并且执行大量查找比扫描表更慢。
为了利用索引,您需要减少所选行的数量,或在索引中包含n
以获得完整的“覆盖”索引。
答案 2 :(得分:0)
您可能让MySQL使用Index Hint Syntax的某个索引。
答案 3 :(得分:-1)
只是预感,在后面有一点经验,尝试将引擎从MyISAM更改为InnoDB。 MyISAM在许多录音和其他错误方面存在一些问题,InnoDB现在更好了。 此外,从MySQL 5.5开始,默认引擎是InnoDB:http://dev.mysql.com/doc/refman/5.5/en/innodb-default-se.html