探究sql中count(1)、count()与count(列名)的区别以及效率对比

经常会在网上看到一些sql优化建议不使用Count(* )而是使用Count(1),从而可以提升性能,给出的理由是Count( )会带来全表扫描。但是做了对比试验发现,其实效率是基本一样的。
首先解读下:count() 是一个聚合函数,函数的参数不仅可以是字段名,也可以是其他任意表达式,该函数作用是统计符合查询条件的记录中,函数指定的参数不为 NULL 的记录有多少个。假设 count() 函数的参数是字段名,如下:
select count(1) from icaAccountingBill
select COUNT(
) from icaAccountingBill
select count(BillNo) from icaAccountingBill ----效率最慢
在这里插入图片描述

首先解读区别:

count(name)
是统计icaAccountingBill 表中,name 字段不为 NULL 的记录有多少个。所以说SQL Server必须读取该col的每一行的值,然后确认下是否为NULL,然后在进行计数。
count(1)
是统计icaAccountingBill 表中,1 这个表达式不为 NULL 的记录有多少个。1 这个表达式就是单纯数字,它永远都不是 NULL,所以上面这条语句,其实是在统计icaAccountingBill表中有多少个记录。
count(*)
实际上可以理解count()只是返回表中行数,因此SQL Server在处理count()的时候只需要找到属于表的数据块块头,然后计算一下行数就行了,而不用去读取里面数据列的数据。
COUNT()在SQL Server中只需要找出具体表中不为NULL的行数即可,也就是所有行(如果一行值全为NULL则该行相当于不存在)。那么最简单的执行办法是找一列NOT NULL的列,如果该列有索引,则使用该索引,当然,为了性能,SQL Server会选择最窄的索引以减少IO。

没有主键和索引的情况下:

在这里插入图片描述

没有索引的情况下:自动找到主键索引

在这里插入图片描述

有索引的情况下:

在这里插入图片描述

在这里插入图片描述

#dbcc show_statistics('NBSAW0106.dbo.icaAccountingBill',IDX_icaAccountingBill_IDX_FOrgId)----显示索引的语法

结论是:如果该表只有一个主键索引,没有任何二级索引的情况下,那么COUNT()和COUNT(1)都是通过通过主键索引来统计行数的。如果该表有二级索引,则COUNT(1)和COUNT()都会通过占用空间最小的字段的二级索引进行统计,这里统计行数的操作,查询优化器的优化方向就是选择能够让IO次数最少的索引,也就是基于占用空间最小的字段所建的索引(每次IO读取的数据量是固定的,索引占用的空间越小所需的IO次数也就越少)。主键索引是聚簇索引(包含了KEY,除了KEY之外的其他字段值,事务ID和回滚指针)所以主键索引一定会比二级索引(包含KEY和对应的主键ID)大,也就是说在有二级索引的情况下,一般COUNT()都不会通过主键索引来统计行数,在有多个二级索引的情况下选择占用空间最小的。
因此,如果某个表上Count(*)用的比较多时,考虑在一个最短的列建立一个单列索引,会极大的提升性能。

猜你喜欢

转载自blog.csdn.net/weixin_45091053/article/details/129696360