经常用到count统计记录数,表又超级大,这时候sql执行很慢,就是走索引,也是很慢的,怎么办呢?

1.这个时候我们就要想为什么这么慢:根本原因是访问的数据量太大,就算只计算记录数也是很慢的。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

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)

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄