我有一张桌子:
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;
Run Code Online (Sandbox Code Playgroud)
我对此表运行的查询是:
SELECT id, d, SUM(n)
FROM p
WHERE rtime BETWEEN '2012-08-25' AND DATE(now())
GROUP BY id, d;
Run Code Online (Sandbox Code Playgroud)
我explain
在一个小表(2 条记录)上运行这个查询,它告诉我它将使用我的主键索引:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 1 | Using where; Using temporary; Using filesort
Run Code Online (Sandbox Code Playgroud)
当我在具有 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
Run Code Online (Sandbox Code Playgroud)
显然,这是极其缓慢的。
我试过丢失GROUP BY
甚至将其更改BETWEEN
为简单的“>”,但它仍然不会使用密钥。
我唯一一次让它使用密钥是在我使用'rtime = ..'
.
我应该注意,所有这些数据实际上只在一周前发生,所以当我尝试获取时,rtime > 3-days-ago
我期望从这 3.5 亿条记录中获得很大一部分。
这个查询应该每 15 分钟运行一次,所以目前 30-40 分钟的执行时间是绝对不能接受的。
我如何构造查询以使其使用索引,或者我应该如何索引表以获得最快的性能?
桌子大小不是小人。这是估计的行数。
在这种情况下,查询优化器(MyISAM、以 rtime 开头的键等)将执行以下操作:
步骤 1 取决于与 MyISAM 表一起保存的“统计信息”。统计数据通常非常准确,但可能会变得不那么准确。ANALYZE TABLE 是解决这个问题的方法。(我认为我从未见过需要每月运行 ANALYZE;通常根本不需要它。)
to-INDEX-or-not-to-INDEX 问题的原因是这样的......使用 INDEX 时,执行必须在索引“行”和数据行之间反弹。数据行可能随机分散,导致(可能)大量 I/O。因此,在某个时间点之后最好进行“表扫描”。
归档时间: |
|
查看次数: |
1599 次 |
最近记录: |