3

我有一张桌子:

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';
4

4 回答 4

1

您的查询:

...WHERE rtime between '2012-08-25' and date(now()) group by id, d;

使用 rtime,并按 id 和 d 分组。至少您应该按rtime. 您可能还想尝试rtime, id, d, n按此顺序进行索引,但是当您这样做时,您会看到您的索引将包含或多或少与您的表相同的数据。

优化器可能会进行一些计算并得出结论,使用索引并不值得。

我会rtime单独留下一个索引。真正的关键是有多少记录匹配WHERE- 如果它们只是几个,阅读索引并在表中跳来跳去很方便。如果它们是多个,则最好顺序扫描整个表,从而节省来回读取。

查询从这 3.5 亿中获得了很大一部分——我会说几百万

好吧,那么很可能快速从索引中提取半万条记录,然后从主表中来回穿梭恢复那半万条记录的累积成本,超过打开主表的成本,并在此过程中对所有 350M 记录进行分组和汇总。

在这种情况下,如果您总是(或大部分时间)在 上运行聚合查询rtime,并且该表是一个累积(历史)表,并且每对夫妇(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当天总和的夫妇有一个条目;该表按比例缩小,查询速度更快。这假设您的数量相对较少,(id, d)并且它们中的每一个每天都会在主表中生成大量行。

每对每分钟记录一次,聚合应该可以将速度提高三个数量级以上(相反,如果您每天两次使用大量不同的传感器,那么好处将可以忽略不计)。

于 2012-08-28T12:57:11.800 回答
1

在您的第二个查询中,日期范围将返回太多行,以至于 MySQL 决定不使用索引。它这样做是因为n不包含在索引中。非覆盖索引仍然是查找,并且进行大量查找比扫描表要慢。

为了利用索引,您需要减少选定行的数量,或者包含n在索引中以获得完整的“覆盖”索引。

于 2012-08-28T13:29:54.463 回答
0

您可能让 MySQL 使用带有Index Hint Syntax的某个索引。

于 2012-08-28T15:27:01.950 回答
-1

只是一个预感,在后面有点经验,尝试将引擎从 MyISAM 更改为 InnoDB。MyISAM 在许多录音和其他错误方面存在一些问题,而 InnoDB 现在更好了。此外,从 MySQL 5.5 开始,默认引擎是 InnoDB:http ://dev.mysql.com/doc/refman/5.5/en/innodb-default-se.html

于 2012-08-28T12:57:02.923 回答