首先要了解使用COUNT()与其它替代方法之间有何不同,以及这个不同的成因。COUNT()的完整语法是:
COUNT ( { [ ALL | DISTINCT ] expression } | *
) )
其中,expression可以是任意表达式,但不能处理唯一标识符,文本,二进制或图像数据,也不能使用聚合函数与子查询。虽然表达式大多都是针对表中的一个列,但ALL是缺省的,所以COUNT(expression)等价于COUNT(ALL
expression)。
COUNT(*)返回表的所有纪录数,而COUNT(expression)则返回符合表达式计算结果的非空纪录数。通常情况下,COUNT(DISTINCT
expression)将相同的纪录只计算为一个。可以看到,根据不同的COUNT()描述,可以得到不同的查询结果。
如前所说,有人以为COUNT(columnname)比COUNT(*)要快,因为COUNT(*)必须读取所有列的纪录(就象运行SELECT * FROM
MYTABLE指令),而COUNT(columnname)只需读取指定列的纪录。这个理解是错误的,有好几个理由。
首先,如果SQL Server不读取整行纪录就无法得到单个列的内容。SQL Server用磁盘上8KB的数据页来储存各行纪录。这些页面中安放一行或多行纪录(取决于每行纪录的大小。在有些意外情况下,一行纪录可能大于8060
字节),当SQL Server要处理这些页面数据时就将数据读到内存(RAM)中。为确定单行(或多行)纪录的值,要将完整的磁盘页读到内存中。这些页面可能已经缓存在内存,这样就会加快运行速度。但SQL仍然要从内存中读取整页的数据来检查一行纪录中的某个列数据。
因为只要求获得纪录数(行数),SQL Server不是读取这些数据页,而是读取索引数据 - 如果有索引的话。索引的存储方法与数据一样,也使用一个8
KB的索引页。索引总是比整行数据要小(索引只包括数列甚至一列的数据),一个索引页可以安放比一个数据页更多行的纪录。这意味着SQL Server用索引页检查纪录数时读取的页面数量比用数据页要少,这是好事。
不但COUNT(索引域名)这样做,COUNT(*)同样也使用索引来计算行数。有时,COUNT(columnname)中指定的列不是索引列,而表中有其它列做索引。在这种情况下,COUNT(*)可以使用索引列来计算纪录数,而COUNT(非索引域名)就不得不通过读取数据页来计算非空纪录数了。