MySQL超大表如何提高count速度
经常用到count统计记录数,表又超级大,这时候sql执行很慢,就是走索引,也是很慢的,怎么办呢?
1.这个时候我们就要想为什么这么慢:根本原因是访问的数据量太大,就算只计算记录数也是很慢的。
2.如何解决?减少数据访问量。
3.怎么才能减少访问量呢?更小的索引。
4.怎么能使索引更小呢?创建前缀索引。
至此我们的方案出来了!下面看看具体的:
表结构:
CREATE TABLE `sbtest3` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`k` int(11) NOT NULL DEFAULT '0',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k_3` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=5000001 DEFAULT CHARSET=latin1;
执行count花费3.58秒,不能接受!!!!!!
select count(*) from sbtest3;
+----------+
| count(*) |
+----------+
| 5000000 |
+----------+
1 row in set (3.58 sec)
看看执行计划,走的是k_3索引。
explain select count(*) from sbtest3;
+----+-------------+---------+-------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | sbtest3 | index | NULL | k_3 | 4 | NULL | 4804854 | Using index |
+----+-------------+---------+-------+---------------+------+---------+------+---------+-------------+
创建一个短索引。
create index idx_sbt3_c on sbtest3(c(1));
看执行计划选择了这个短索引。
explain select count(*) from sbtest3;
+----+-------------+---------+-------+---------------+------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+------------+---------+------+---------+-------------+
| 1 | SIMPLE | sbtest3 | index | NULL | idx_sbt3_c | 1 | NULL | 4804854 | Using index |
+----+-------------+---------+-------+---------------+------------+---------+------+---------+-------------+
执行一下sql花费0.59秒,还能接受。
select count(*) from sbtest3;
+----------+
| count(*) |
+----------+
| 5000000 |
+----------+
1 row in set (0.59 sec)
现实环境如果带where条件怎么办?
如下我想获得id>10000的记录数,花费2.55秒,不可接受!!!!
select count(*) from sbtest3 where id>10000;
+----------+
| count(*) |
+----------+
| 4990000 |
+----------+
1 row in set (2.55 sec)
可以换种思路:
先得到相反条件过滤数据多的记录数,然后再获得总数,然后相减,速度也是有很大的提高。
select count(*) from sbtest3 where id<=10000;
+----------+
| count(*) |
+----------+
| 10000 |
+----------+
1 row in set (0.08 sec)
select count(*) from sbtest3;
+----------+
| count(*) |
+----------+
| 5000000 |
+----------+
1 row in set (0.59 sec)
select 5000000 - 10000;
+----------------+
| 5000000 - 9999 |
+----------------+
| 49900010|
+----------------+
1 row in set (0.00 sec)