刚开始用sql Server的时候,我没有用显示执行计划来对查询进行分析。我曾经一直认为我递交的SQL查询都是最优的,而忽略了查询性能究竟如何,从而对“执行计划”重视不够。在我职业初期,我只要能获取数据就很开心,而不去考虑数据是如何返回的,“执行计划”对我的查询作了什么工作。我以为sql Server会自己去处理查询的性能问题的。作为一个刚进入IT行业或者刚学到新技术的软件工程师,在编写代码前不太可能有时间去学习其实必须掌握的知识。也许这是因为IT行业竞争太激烈的缘故。
随着时间的流逝,数据库容量慢慢变大了。终于某天,客户对应用系统的查询性能感到不满意了。他面带怒容来找我,抱怨由于查询太慢,使得他需要花更多的时间来处理公务。最初,我建议客户升级其系统资源,例如作为临时解决方案,增加硬盘容量。虽然硬盘价格现在很便宜了,但是客户还是要求我提供一个永久性的解决方案,检查和好好调试查询语句,来替代那种无休止地升级资源的临时方案。因为客户的满意度对IT行业来说是十分重要的,因此我不得不考虑他的个人建议。我答应他一定会检查和调整我的代码。
如何入手呢?
在刚进入IT行业时,我知道sql Server的基础只是。说实话,向客户承诺检查系统的时候,我还没有一点入手的头绪。不过我相信我可以通过GOOGL和BOL来获取相应的信息。
我阅读了一些关于sql Server的书籍,BOL,以及在网上搜索的信息。于是我知道了“显示执行计划”的概念。可以在查询管理器中将该选项的开关设置为ON.“显示执行计划”是一个图形化工具,可以帮助开发者和DBA分析,优化查询,从而改善性能。
“显示执行计划”中不同的任务具有不同的图标。本文中我主要对“Table Scan”、“Index Scan”、“Index Seek”、“Cluster Index Scan”以及“Clustered Index Seek”感兴趣。也许在以后,可以对别的任务进行另外介绍。
时间以F1方程式的速度开始流逝,我觉得该是我全面理解“Table Scan”、“Index Scan”、“Index Seek”、“Clustered Index Scan”、和“Clustered Index Seek”如何工作的时候了。
我准备开始分析并优化我的查询。在分析之前,我想到了一些问题。
- MS-sql Server什么时候使用"Table Scan"?
- MS-sql Server什么时候使用"Index Scan"?
- MS-sql Server什么时候使用"Index Seek"?
- MS-sql Server什么时候使用"Clustered Index Scan"?
- MS-sql Server什么时候使用"Clustered Index Seek"?
我主要关注sql Server是根据什么来使用“执行计划”分析查询的。在经过一段时间学习后,我了解了一些相关知识。这些知识应该对开发和DBA新手有帮助。于是我决定写这篇文章,共享我的知识以帮助别人来理解“执行计划”。
如果你喜欢,可以慢慢读完,也可以在sql Server上,模拟我下面做的实验。
开始入手
为了解释“显示执行计划”中的“Table Scan”、“Index Scan”、“Index Seek”、“Clustered Index Scan”和“Clustered Index Seek”,先创建新表,并添加一些示例数据进去。下面是创建新表的脚本:
Create Table PerformanceIssue |
表创建后需要添加一些数据。使用下面的脚本添加100,000条记录进去。脚本执行时间可能比较长,请耐心等待其执行完毕。
Declare @Loop Int |
脚本成功执行后,数据就添加进去了。
用下面语句来看一下表的内容:
Select PRID,PRCode,PRDesc |
由于记录较长,因此这里就不列出查询结果了。
正如我前面讲到,我想解释何时会有“Table Scan”、“Index Scan”、“Index Seek”、“Clustered Index Scan”和“Clustered Index Seek”。上述哪个会改善性能呢?
当sql Server返回数据时,我们想知道sql Server采取何种扫描机制来协助获取数据。首先看一下“Table Scan”。我们想了解什么时候“Table Scan”会产生。
选择“显示执行计划”或者使用热键“Alt + Q”来激活“显示执行计划”,当然也可以用快捷键“Ctrl+K”。
看一下执行下面查询后的“执行计划”结果。
上面的“执行计划”中,sql Server用到了“Table Scan”。我问自己为什么会有“Table Scan”,sql Server是根据什么来使用该方法的。难道是因为我想获取所有100,000条记录吗?于是我换了一个角度进行思考,如果来避免查询中出现“Table Scan”呢?此时我对sql Server的扫描机制还不是很清楚,那么该如何优化查询呢?下面的SELECT查询中仅选择两列:[PRID,PRCode]。
查询执行后,执行计划和第一个查询一样。于是将查询改变为只检索一个字段 [PRID]。
Select PRID |
查询执行后,执行计划仍然和第一个查询的相同。对“Estimated row size”属性不需要太大关注。意思我立刻决定只获取一条记录,看看执行计划会如何。查询语句如下:
执行完成后,执行计划显示:
那么,我需要想其它办法来避免“Table Scan”。首先我想到应该给表加上索引。于是我在PRID字段上创建非聚集索引。添加了索引后是否就能避免“Table Scan”?下面我们开始讨论关于“Index Scan”和“Index Seek”的主题。
Index Scan 和 Index Seek