MySQL之count(1)和count(*)的区别

闲扯

很久以前,有一次我写了一个SQL:

select count(*) from test;

然后这个代码被我的其中一家公司的MySQL专家看到了,叫我过去说:

你难道不知道咱们不允许写count(*)吗?你不知道count(1)更快吗?

说完二话没说把我的SQL改了。

我自然是惴惴不安。

谁对谁错

先说结论,我是对的,count(*)不但不慢,count(1)也会和count(*)走一样的执行计划。

我们先看这个表:

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `xid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `xid` (`xid`)
) ENGINE=InnoDB;

现在看看count(*)的执行计划:

可以看到,这里出现了索引覆盖,也就是说优化器选择了xid这个索引进行了覆盖。

那么看看count(1)的执行计划:

结果是完全一样的。其实优化器现在是很智能的,不会因为你写了count(1)它就能出现什么黑科技,还是老老实实的一行一行在索引上统计,但是好处是不用二次回表检索了。

那么如果是count某个列呢?

我们首先给这个表里插入一条奇怪的数据:

insert into test(xid) values (null);

这个时候执行

select count(xid) from test;

结果也是很奇怪:

明显有问题,count(*)的结果是11。

看看执行计划:

可以看到还是索引覆盖的,而且真的扫描了11行。

MySQL在处理这种count(columnName)的时候会自动的把为null的列忽略掉,因此带来了看似不正确的结果。

《高性能MySQL》上关于NULL的论述中专门提到了,对于要索引的列,最好设置成not null。

这个现象也是该论调的一个有力证明。

写给杠精

可能有人会问,如果这个表上没有二级索引呢?岂不是count(1)更快?

其实不是这样的,我把表的索引去掉,这是现在的表结构:

这是两种SQL的执行计划:

还是完全一样。

其实想想,如果Oracle自己都发现了这个奇技淫巧,那么他们的工程师也会对这个进行优化的。

结论

直接count(*)就好,count(1)快这个论调就是个MySQL日常迷信。

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值