我有一个较大但很窄的InnoDB表,记录约为9m。在桌面上执行count(*)
或count(id)
非常慢(6秒以上):
DROP TABLE IF EXISTS `perf2`;
CREATE TABLE `perf2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`channel_id` int(11) DEFAULT NULL,
`timestamp` bigint(20) NOT NULL,
`value` double NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ts_uniq` (`channel_id`,`timestamp`),
KEY `IDX_CHANNEL_ID` (`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
RESET QUERY CACHE;
SELECT COUNT(*) FROM perf2;
虽然声明不经常运行,但优化它会很好。根据{{3}},这应该可以通过强制InnoDB使用索引来实现:
SELECT COUNT(id) FROM perf2 USE INDEX (PRIMARY);
解释计划似乎很好:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE perf2 index NULL PRIMARY 4 NULL 8906459 Using index
不幸的是,这句话和以前一样慢。根据{{3}},我也尝试过优化表格。
在InnoDB上优化COUNT(*)
性能的方法是什么?
答案 0 :(得分:17)
目前我已经通过使用这种近似解决了这个问题:
EXPLAIN SELECT COUNT(id) FROM data USE INDEX (PRIMARY)
使用InnoDB时,可以从解释计划的rows
列中读取大致的行数,如上所示。当使用MyISAM时,这将保持EMPTY,因为表格参考正在被优化 - 所以如果空的回退到传统的SELECT COUNT
。
答案 1 :(得分:14)
从MySQL 5.1.6开始,您可以使用Event Scheduler并定期将统计数据插入统计数据表。
首先创建一个表来保存计数:
CREATE TABLE stats (
`key` varchar(50) NOT NULL PRIMARY KEY,
`value` varchar(100) NOT NULL);
然后创建一个事件来更新表:
CREATE EVENT update_stats
ON SCHEDULE
EVERY 5 MINUTE
DO
INSERT INTO stats (`key`, `value`)
VALUES ('data_count', (select count(id) from data))
ON DUPLICATE KEY UPDATE value=VALUES(value);
它并不完美,但它提供了一个独立的解决方案(没有cronjob或队列),可以轻松定制,以便按照计数所需的新鲜度运行。
答案 2 :(得分:12)
基于@Che代码,您还可以在INSERT和UPDATE上使用触发器来执行perf2,以使stats表中的值保持最新。
CREATE TRIGGER `count_up` AFTER INSERT ON `perf2` FOR EACH ROW UPDATE `stats`
SET
`stats`.`value` = `stats`.`value` + 1
WHERE
`stats`.`key` = "perf2_count";
CREATE TRIGGER `count_down` AFTER DELETE ON `perf2` FOR EACH ROW UPDATE `stats`
SET
`stats`.`value` = `stats`.`value` - 1
WHERE
`stats`.`key` = "perf2_count";
这样做的好处是可以消除执行计数(*)的性能问题,并且只会在表 perf2
中的数据更改时执行答案 3 :(得分:-4)
select max(id) - min(id) from xxx_table where
....
这将使用“选择经过优化的表”,并且速度非常快!
注意max(id) - min(id)
实际上大于count(1)
。