SQL Server查询性能优化――堆表、碎片与索引(一)(二)
有内部碎片。
b) 此表的扫描密度只有98%,也就是说理论上的区的数量与实现上区的数量之比为1:1,也就是说基本上没有外部碎片,也就是说每个区的利用率相当高。
如下图:
备注:对于上图中的一些字段说明,见(一)。
2.SQL查询语句与查询执行计划成本
--查询语句:
SET STATISTICS IO on
go
SET STATISTICS TIME on
go
go
SET STATISTICS TIME on
go
select * from T_EPZ_INOUT_ENTRY_DETAIL where entry_apply_id='31227000034000090169'
go
SET STATISTICS IO off
go
SET STATISTICS IO off
go
SET STATISTICS TIME off
go
go
3.查询所需要的时间与I/O
SQL Server 执行时间:
CPU 时间 = 0 毫秒,耗费时间 = 0 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,耗费时间 = 98 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,耗费时间 = 0 毫秒。
(所影响的行数为 13 行)
表 'T_EPZ_INOUT_ENTRY_DETAIL'。扫描计数 1,逻辑读 3 次,物理读 2 次,预读 0 次。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,耗费时间 = 30 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,耗费时间 = 0 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,耗费时间 = 0 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,耗费时间 = 0 毫秒。
比较以上三者的各种关键值,就可以看出性能的提升程度。
物理操作
逻辑操作
I/O成本
CPU成本
成本
子树成本
逻辑读
物理读
预读
例一:堆表高度碎片化
Table Scan 逻辑运算符和物理运算符检索 Argument 列内指定表中的所有行
同左
3.61
0.0342
3.645123
3.65
4825
6
19672
例二:堆表低度碎片化
同上
同左
0.464
0.0171
0.963642
0.963
1205
0
1209
例三:表(带主键)
Clustered Index Seek 逻辑运算符和物理运算符利用索引的查找能力从聚集索引中检索行
同左
0.0032
0.000086
0.003289
0.00328
3
2
0
例一/例二/例三
1128/145/1
397/198/1
1108/292/1
1112/293/1
1608/401/1
3/0/1
16/1/0
对表中列的说明:
物理操作:使用的物理运算符,例如 Hash Join 或 Nested Loops。
逻辑操作:与物理运算符匹配的逻辑运算符,如 Join 运算符。
I/O 成本:用于操作的所有 I/O 活动的预计成本。该值应尽可能低。
CPU 成本:用于操作的所有 CPU 活动的预计成本。
成本:查询优化器执行此操作的成本,包括此操作的成本占查询总成本的百分比。由于查询引擎选择最高效的操作执行查询或执行语句,因此该值应尽可能低。
子树成本:查询优化器执行此操作及同一子树内位于此操作之前的所有操作的总成本。
在本文的三个例子中,预读值最高的为19672,最低的为0,物理读的值最高为6,最低为0,而逻辑读的值最高为4825,最低为3。
那么我在服务器上 执行查询时的过程是怎么样的呢?以例一为例。
首先,SQL Server会开始检查完成查询所需要的数据是否在数据缓冲区中,它会很快地发现这些数据不在数据缓冲区中, 并启动预读机制将它所需要的数据页读取到数据缓冲区中,但是由于数据页碎片严重情况,需要多次切区,大大提升了I/O的消耗,如例一中读取19672次,所以当碎片非常严重时,I/O读取非常频繁,多读取了4倍的数据页。
其次,如例一,当SQLServer检查是否所需要的全部数据都已经在数据缓冲区时,会发现已经有4819个数据页在数据缓冲区中,还有六个数据页不在,它就会立即再次读取磁盘,所以有了6次的物理读,在将所需要的页读到数据缓冲区。一旦所有的数据都在数据缓冲区后,SQL Server就可以处理查询了。