【SQLServer】SQLServer执行计划运算符-第1部分
2022-09-27 20:56 abce 阅读(260) 评论(0) 编辑 收藏 举报
在开始使用查询执行计划运算符之前,我们将使用以下T-SQL脚本创建一个新的简单表并用测试数据填充它:
CREATE TABLE ExPlanOperator ( ID INT IDENTITY (1,1), First_Name VARCHAR(50), Last_name VARCHAR(50), Address VARCHAR(MAX) ) GO INSERT INTO ExPlanOperator VALUES ('AA','BB','CC') GO 1000 INSERT INTO ExPlanOperator VALUES ('DD','EE','FF') GO 1000
SQLServer表扫描运算符(Table Scan Operator)
创建的ExPlanOperator表是一个堆表,由于没有在该表上创建聚集索引,因此数据行在每个数据页中不以任何特定顺序存储在该表中。
因此,为了返回对该表的任何查询的结果,SQL Server引擎将使用Table Scan运算符逐行扫描整个表。
假设我们运行以下T-SQL语句,该语句在包含查询的实际执行计划后从ExPlanOperator测试表中检索所有记录以查看其行为方式。你将从生成的SQL查询执行计划中看到,SQL Server引擎将使用Table Scan运算符扫描所有整个表行,以检索请求的数据,如下所示:
当我们尝试通过添加WHERE子句来获取特定记录集时,SQL Server引擎将以相同的方式运行。它将再次使用Table Scan运算符扫描所有整个表行,因为该表上没有创建索引来帮助数据检索,如下所示:
如果我们在测试表的ID列上创建一个非聚集索引,使用下面的CREATE INDEX T-SQL语句:
CREATE INDEX IX_ExPlanOperator_ID ON ExPlanOperator (ID)
然后运行相同的SELECT语句来检索一组特定的ID。将看到SQL Server引擎更喜欢逐行扫描整个表,而不是使用创建的索引。这种行为有很多原因。例如,索引没有用,表包含少量行或者查询将返回大部分表行,如下所示:
SQLServer聚集索引扫描运算符(Clustered Index Scan Operator)
当在表上创建聚集索引时,该表将从堆表转换为聚集表。
聚集表是在表的一列或多列上具有预定义聚集索引的表,该索引根据聚集索引键定义数据页内行的存储顺序和表内页的顺序。
让我们删除之前在ExPlanOperator表上创建的非聚集索引,并将其替换为ExPlanOperator表上ID列上的聚集索引,使用下面的T-SQL脚本:
DROP INDEX IX_ExPlanOperator_ID on ExPlanOperator CREATE CLUSTERED INDEX IX_ExPlanOperator_ID ON ExPlanOperator (ID)
如果我们运行从测试表中检索所有行的相同SELECT查询,并包含查询的实际SQL查询执行计划,你将看到Table Scan运算符将被Clustered Index Scan运算符替换,具有相同粗细的箭头,如下图所示:
从之前的SQL查询执行计划中,SQL Server引擎决定使用聚集索引扫描运算符,尽管它会遍历所有索引行,类似于表扫描运算符的行为方式。这是因为,聚集索引可以被认为是对底层表的排序替换,它除了索引键之外,还存储了索引的最低级别的所有表数据,也称为叶子。如果由于统计数据过期而没有有用的非聚集索引,或者查询将返回所有或大部分表行,SQL Server引擎将决定使用聚集索引扫描运算符扫描所有聚集索引行是比使用索引提供的键更快。
SQLServer聚集索引搜索运算符( Clustered Index Seek Operator)
如果通过在WHERE子句中添加数据过滤语句来修改先前的SELECT查询以提高效率,这会限制从表返回的行数,SQL Server查询优化器决定使用一种非常快速的方法来检索数据,使用Clustered Index Seek运算符,如下图:
SQL Server查询优化器不会遍历所有表行,而是定位适当的聚集索引并找到要检索所需的行,方法是向SQL Server存储引擎提供指令以根据所选的键值识别所需的行指数。除了使用聚簇索引查找运算符快速处理数据以检索所需的行之外,检索其余列不需要额外的步骤,因为表的完整排序副本存储在聚簇索引的叶级节点中.
SQL Server非聚集索引搜索运算符(Non-clustered Index Seek Operator)
当SQL Server查询优化器发现查询请求的所有数据都可以由可用索引提供时,它将使用Index Seek运算符对该非聚集索引执行查找。
假设我们使用下面的CREATE INDEX T-SQL命令在ExPlanOperator测试表的 First_Name列上创建了一个非聚集索引:
CREATE INDEX IX_ExPlanOperator_FirstName on ExPlanOperator(First_Name)
然后在包含查询的实际执行计划后,运行以下检索 First_Name 列的 SELECT 语句,如下所示:
将从SQL查询执行计划中看到,SQL Server查询优化器发现创建的索引包含提交的查询请求的所有数据,并且检索这些数据的最快方法是查找该非聚集索引。回想一下,非聚集索引只存储索引键值和指向其余列的指针。如果SQL Server查询优化器无法在该索引中找到所有请求的数据,如果是聚簇表,它将在聚簇索引中查找附加数据;如果是堆表,就在基础表中。由于在查找过程中执行的额外I/O操作而影响查询性能,我们将在本系列的后面看到。