SQL性能调优实践——SELECT COUNT

最近想深入学习SQL,在网上搜索到一些SQL 优化的资料要么是张冠李戴,Oracle 优化的资料硬是弄成啦MS SQL 优化的资料,而且被很多人转载,收藏,有些要么有些含糊不清,好像是那么回事,也没经过验证,实践出真知!下面是我对SELECT COUNT(*), SELECT COUNT(1),SELECT COUNT (0), SELECT COUNT(Field)等孰优孰劣的测试结果,如果测试方法有什么不足,也希望大家给点建议。

 

首先我们来看看测试的机器、以及开发环境吧:双核处理器 T6670  2G DDR2的内存 数据版本如下图所示:

  然后建一个简单的测试表

CREATE TABLE Employee

(

    [EmployeeID]        INT IDENTITY(1,1),  --雇员ID

    [EmployeeName]      NVARCHAR(20)     ,  --雇员姓名

     [SEX]               BIT              ,  --性别

     [Department]        NVARCHAR(20)     ,  --部门

     CONSTRAINT [PK_Employee_ID_Name] PRIMARY KEY (EmployeeID, EmployeeName) 

)

--插入一百万数据

DECLARE @Index INT;

SET @Index = 1;

WHILE @Index < 1000000

BEGIN

    INSERT INTO Employee

    VALUES('Employee' + STR(@Index), '0', '技术部门');

    SET @Index = @Index + 1;

END

--建立非聚集索引

CREATE INDEX IDX_Employee_Department ON Employee([Department]);

好,到目前为止我们已经把测试用的表、数据都弄好啦,接下来我们来看看执行一次SELECT COUNT 的使用时间

Code Snippet

  1. DBCC DROPCLEANBUFFERS;
  2.  
  3. DBCC FREEPROCCACHE;
  4.  
  5. SET STATISTICS TIME ON;
  6.  
  7. SELECT COUNT(0) FROM Employee
  8.  
  9. SET STATISTICS TIME OFF;

 

我们会得到下面的输出结果

DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。

DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。

 

SQL Server 执行时间:

   CPU 时间= 219 毫秒,占用时间= 1033 毫秒。 

接下来我们来看看各种Count的实际执行计划,截图如下

 

我很纳闷为什么执行计划都是一样的,希望有高手能解答。

接下来,那么我们把上面的脚本执行10次,把每次得到的数据记录下来,然后我们依次用

SELECT COUNT(1) FROM Employee、 SELECT COUNT(*)  FROM Employee

等替换SELECT COUNT(0) FROM Employee 脚本,如下所示

DBCC DROPCLEANBUFFERS;

DBCC FREEPROCCACHE;

SET STATISTICS TIME ON;

SELECT COUNT(1) FROM Employee

SET STATISTICS TIME OFF; 

 

依葫芦画瓢每段脚本执行10次,最后我们求得到的结果的平均值,为了形象显示,我用Excel把数据显示如下: 

 SELECT COUNT(1) FROM Employee

 

SELECT COUNT(0) FROM Employee

 

SELECT COUNT(*) FROM Employee

 

SELECT COUNT(EmployeeName) FROM Employee

 

从实验结果来看,执行快慢的顺序为: COUNT(EmployeeName) > COUNT(0) ~= COUNT(1) > COUNT(*);从实验结果来看,我们至少验证了 COUNT(0) ~= COUNT(1) > COUNT(*)的结论,网上有篇帖子《SQL Server 索引结构及其使用》篇所下的结论count(*)不比count(字段)慢 显然是不严谨的,他只做了一次实验,而我们这里是10次结果的平均值。那么现在问题来了,为什么COUNT(EmployeeName)要快于COUNT(0) >= COUNT(1),它如果不是主键、字段没有索引呢?网上不是有些资料显示COUNT(1)效率最高,速度最快吗? 我们10次得到平结值有没有误差呢?抽样能否反映事实呢?下面我用这个方法来大量获得语句执行时间,然后求平均值,(我觉得这方法应该是可以反映实际CPU时间的)如果有不妥的地方,也希望大家指正。 创建下面一个表



CREATE TABLE ExcuteTime

(

    [Type]     VARCHAR(10),    --不同COUNT类型

     [CpuTime]    FLOAT         --语句执行的毫秒

)

--得到COUNT(1)100次的执行时间

DECLARE @BeginTime DATETIME;

DECLARE @Num INT;

SET @Num = 1;

WHILE @Num <= 100

BEGIN

SET @BeginTime = GETDATE();

SELECT COUNT(1) FROM Employee;

INSERT INTO ExcuteTime

VALUES('Count(1)', DATEDIFF(ms, @BeginTime,GETDATE()));

SET @Num = @Num + 1;

END

GO



然后也依次得到其它几种SQl 的执行时间,另外我们也把COUNT(Department)得数据加入进来,下面是我得到的实验结果的平均值

COUNT(1) COUNT(0) COUNT(*) COUNT(EmployeeName) COUNT(Department)
100.09 99.27 100.28 65.95 134.13

      

 

    

 

数据显示也与上面的测试结果相一致,虽然得到了这些结果,由于统计偏差缘故,COUNT(0)比 COUNT(1) 稍稍快些,这个是完全可以忽略,因为我统计的次数比小,很容易造成偏差,COUNT(*) 接
近于COUNT(1),估计是由于数据缓存缘故,其实我们从实验结果可以看出统计数据的速度:
对索引字段统计要快于COUNT(1),原因是COUNT(1)是要走全表扫描,而COUNT(1) 快于COUNT(*)
,是因为COUNT(*)走全表扫描的开销要大于COUNT(1), 至于统计非索引字段COUNT(Department),比较偏大的,则让我有点纳闷,估计是统计偏差缘故。

时间: 2024-05-26 08:07:27

SQL性能调优实践——SELECT COUNT的相关文章

SQL性能调优实践&amp;mdash;&amp;mdash;SELECT COUNT

最近想深入学习SQL,在网上搜索到一些SQL 优化的资料要么是张冠李戴,Oracle 优化的资料硬是弄成啦MS SQL 优化的资料,而且被很多人转载,收藏,有些要么有些含糊不清,好像是那么回事,也没经过验证,实践出真知!下面是我对SELECT COUNT(*), SELECT COUNT(1),SELECT COUNT (0), SELECT COUNT(Field)等孰优孰劣的测试结果,如果测试方法有什么不足,也希望大家给点建议.   首先我们来看看测试的机器.以及开发环境吧:双核处理器 T6

mybatis SQL性能调优

Mybatis SQL性能调优         1.  Mapper层参数为Map,由Service层负责重载       Mapper由于机制的问题,不能重载,参数一般设置成Map,但这样会使参数变得模糊,如果想要使代码变得清晰,可以通过service层来实现重载的目的,对外提供的Service层是重载的,但这些重载的Service方法其实是调同一个Mapper,只不过相应的参数并不一致.     也许有人会想,为什么不在Service层也设置成Map呢?我个人是不推荐这么做的,虽然为了方便,

【北京】淘宝、美团、石墨4位核心工程师分享“Node.js 大规模应用设计以及性能调优实践”

2016年线下活动第一弹: Node.js 大规模应用设计以及性能调优实践 北京 2016. 01. 09 京仪大酒店 会议介绍: 从「现象级」的新潮服务端编程语言真正成为「工业级」,Node.js 依然面临无数的淬炼,特别是在「生产环境」中.邀请到了淘宝.美团.石墨等 Node.js 大规模应用设计以及性能调优的4位核心工程师深入分享. 嘉宾介绍: 1. 淘宝竹暄<Node.js 助力淘宝大促活动> 峰值4万QPS的大促会场催生了百亿成交量的全球狂欢节.支撑着这些玲琅满目的会场和频道页面的,

Oracle性能调优实践中的几点心得

oracle|心得|性能        很多的时侯,做Oracle DBA的我们,当应用管理员向我们通告现在应用很慢.数据库很慢的时侯,我们到数据库时做几个示例的Select也发现同样的问题时,有些时侯我们会无从下手,因为我们认为数据库的各种命种率都是满足Oracle文档的建议.实际上如今的优化己经向优化等待(waits)转型了,实际中性能优化最根本的出现点也都集中在IO,这是影响性能最主要的方面,由系统中的等待去发现Oracle库中的不足.操作系统某些资源利用的不合理是一个比较好的办法,下面把

SQL Server性能调优之缓存

在执行任何查询时,SQL Server都会将数据读取到内存,数据使用之后,不会立即释放,而是会缓存在内存Buffer中,当再次执行相同的查询时,如果所需数据全部缓存在内存中,那么SQL Server不会产生Disk IO操作,立即返回查询结果,这是SQL Server的性能优化机制. 一,主要的内存消费者(Memory Consumer) 1,数据缓存(Data Cache) Data Cache是存储数据页(Data Page)的缓冲区,当SQL Server需要读取数据文件(File)中的数

《T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数》——1.1 窗口函数的背景

1.1 窗口函数的背景 T-SQL性能调优秘笈--基于SQL Server 2012 窗口函数 在开始学习具体的窗口函数之前,先了解其背景和内涵,会对后续的学习有所帮助.本节先谈谈窗口函数的背景,解释基于集合方式和基于游标/迭代方式进行查询的不同,以及窗口函数如何对二者的差异进行弥补.最后,本节也提到了窗口函数的替代方法,以及为什么窗口函数会优于其替代方法.注意,尽管窗口函数能非常高效地解决很多问题,但在某些案例中,替代方法会好于窗口函数.第4章会具体谈论对窗口函数的优化,解释在什么情况下,计算

《T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数》——1.6 窗口定义的重复使用

1.6 窗口定义的重复使用 T-SQL性能调优秘笈--基于SQL Server 2012 窗口函数 假设我们需要在同一个查询中调用多个窗口函数,并且部分窗口描述(或所有描述)适用于多个函数.如果我们在所有函数中都给出完整的窗口描述,代码的长度会急速增加,从下面的示例中可以看到问题: 标准SQL对此有解决方法,它有一个叫做WINDOW的子句,允许我们对窗口描述或部分窗口描述进行命名:然后在定义其他窗口--即将被窗口函数使用或用来定义另一个命名窗口时,指代这个命名的窗口描述.从概念上来说,这个子句在

《T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数》——1.5 潜在的额外筛选器

1.5 潜在的额外筛选器 T-SQL性能调优秘笈--基于SQL Server 2012 窗口函数 上面提供T-SQL中的一个变通方法,它可以在不直接支持窗口函数的查询元素里,间接地使用窗口函数.这个变通的方法就是CTE形式的表表达式或派生表.有变通方法当然很好,但表表达式给查询增加了一个层次,也增加了其复杂性.我展示的那些示例都很简单,但可以想象一下,如果本身的查询已经很长和复杂,这样做确实会增加难度.是否有更简单的方法,无须增加查询的层次就可达到目的? 对于窗口函数,SQL Server目前还

《T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数》——1.4 支持窗口函数的查询元素

1.4 支持窗口函数的查询元素 T-SQL性能调优秘笈--基于SQL Server 2012 窗口函数 并不是所有的查询子句都支持窗口函数,相反,仅仅SELECT和ORDER BY子句支持窗口函数.为了帮助大家理解这个约束的原因,我首先要解释查询逻辑处理的概念.然后,我会介绍支持窗口函数的子句,最后,解释如何在其他子句中避开约束. 1.4.1 查询逻辑处理 查询逻辑处理从概念性的角度描述SELECT查询是如何根据逻辑语言的设计进行判断的.它描述了怎样由查询的输入表,经由一系列步骤和阶段,直到查询