SQL Server 执行计划(4) - 执行计划运算符详解1

本文详细介绍了SQL Server执行计划中的四种运算符:表扫描、聚集索引扫描、聚集索引查找和非聚集索引查找。通过示例说明了在不同情况下,SQL Server如何选择合适的运算符进行数据检索,强调了索引在查询优化中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本系列的前几篇文章中, SQL Server 执行计划概述SQL Server 执行计划类型如何分析 SQL 图形执行计划组,我们讨论了 SQL Server 关系引擎为生成执行计划而执行的步骤以及 SQL Server 存储引擎为检索请求的数据或执行修改操作而执行的步骤。

此外,我们阐明了可用于排除查询性能故障的 SQL Server的 查询执行计划的不同类型和格式。最后,我们讨论了图形查询计划的组件以及我们如何对其进行分析。在本文中,我们将介绍第一组 SQL 查询计划运算符。

在开始使用查询执行计划运算符之前,我们将创建一个新的简单表并使用以下 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

表扫描运算符(Table Scan)

上方创建的 ExPlanOperator 表是一个堆表(HeapTable)。因为没有在表上创建聚集索引,所以表中的数据行在每个数据页中没有以任何特定顺序存储,

因此,为了返回对该表的任何查询的结果,SQL Server 引擎将使用表扫描运算符逐行扫描整个表。

假设我们运行下面的 T-SQL 语句,运行时选择包含实际执行计划的选项,以查看它将如何运行。从生成的 SQL 查询执行计划中可以看到,SQL Server 引擎使用了**表扫描运算符(TableScan)**扫描整个表的所有数据行,以检索请求的数据。如下图所示:
表扫描运算符(TableScan)

当我们在查询语句中添加 WHERE 子句来获取特定的记录,SQL Server 引擎的行为方式也是一样的。它还是使用了**表扫描运算符(TableScan)**来扫描整个表的所有数据行,因为该表上没有创建索引来协助数据检索。如下图所示:
表扫描运算符2(TableScan)

如果我们在测试表的 ID 列上追加创建一个非聚集索引,使用下面的 CREATE INDEX T-SQL 语句:

CREATE INDEX IX_ExPlanOperator_ID ON ExPlanOperator (ID)

然后运行相同的 SELECT 语句来检索一组特定的 ID。您将看到 SQL Server 引擎并没有使用新创建的索引来查询数据,而是还是选择了**表扫描运算符(TableScan)**来扫描所有数据行。造成这种行为的原因有很多。例如,索引没有作用,表只包含少量数据行或查询操作将返回大部分数据行。如下图所示:
表扫描运算符3(TableScan)

聚集索引扫描运算符(Clustered Index Scan)

在表上创建聚集索引(Clustered Index)时,该表将从堆表(HeapTable)转换为聚集表(Clustered Table)。聚簇表是在表的一列或多列上具有预定义聚簇索引的表,该索引根据聚簇索引键定义数据页内行的存储顺序和表内页的顺序。

有关群集表结构的详细信息,请参阅SQL Server 表结构概述。有关聚集索引的详细信息,请参阅设计有效的 SQL Server 聚集索引

让我们删除之前在 ExPlanOperator 表上创建的非聚集索引,并使用以下 T-SQL 脚本将其替换为 ExPlanOperator 表中 ID 列上的聚集索引:

DROP INDEX IX_ExPlanOperator_ID on ExPlanOperator
CREATE CLUSTERED INDEX IX_ExPlanOperator_ID ON ExPlanOperator (ID)

如果我们再次运行相同的 SELECT 查询,从我们的测试表中检索所有行,你会看到表扫描运算符(Table Scan)聚集索引扫描运算符(Clustered Index Scan) 替换了,同时箭头厚度与表扫描操作时的箭头厚度是一样的。如下图所示:

聚集索引扫描运算符

在上面的 SQL 查询执行计划中,SQL Server 引擎决定使用聚集索引扫描运算符,尽管它会遍历所有索引数据行。这样做的原因是,聚集索引除了可以作为索引键使用之外,还是底层表数据的排序替换。因为底层表将所有表数据都存储在了索引的最低级别-叶节点中。在统计信息没有包含有用的非聚集索引,或者查询将返回全部或大部分数据行的情况,SQL Server 引擎将会判断使用聚集索引扫描运算符扫描所有聚集索引行,比使用索引提供的键来查找更快。

聚集索引查找运算符(Clustered Index Seek)

如果通过在 WHERE 子句中添加数据过滤语句来修改先前的 SELECT 查询以提高效率,这限制了从表返回的行数。这种情况下,SQL Server 查询优化器会决定使用**聚集索引查找运算符(Clustered Index Seek)**来更高速检索数据。示意图如下:
聚集索引查找运算符

SQL Server 查询优化器将定位到可用的聚集索引,通过向SQL Server 存储引擎直接提供索引键值定位信息,可以快速导航并定位到目标数据行,而不需要遍历所有的表数据行。另外使用聚集索引查找运算符(Clustered Index Seek)时,不需要额外的步骤来检索其余的数据列,因为表的完整排序副本存储在聚集索引的叶级节点中。

非聚集索引查找运算符(Non-clustered Index Seek)

当 SQL Server 查询优化器发现查询请求的所有数据都可以由可用索引提供时,它将使用索引查找运算符对该**非聚集索引(Non-clustered Index)**执行查找。

有关非聚集索引的详细信息,请参阅设计有效的 SQL Server 聚集索引

使用下面的 CREATE INDEX T-SQL 命令在 ExPlanOperator 测试表的 First_Name 列上创建了一个非聚集索引:

CREATE INDEX IX_ExPlanOperator_FirstName on ExPlanOperator(First_Name)

然后运行以下 SELECT 语句来检索 First_Name 列。执行结果及执行计划的图示如下:
在这里插入图片描述

从 SQL 查询执行计划中看到,SQL Server 查询优化器发现创建的索引已经包含查询请求的所有数据,并且检索这些数据的最快方法是寻找非聚集索引,所以使用非聚集索引查找运算符(Non-clustered Index Seek)非聚集索引中仅存储索引键值和指向其余列的指针,如果 SQL Server 查询优化器无法在该索引中找到所有请求的数据,它将在聚集索引(聚集表的情况)或基础表中(堆表的情况)中查找附加数据。但是在查找过程中执行的额外 I/O 操作会影响查询性能,我们将在本系列的后面文章中介绍这种情况。

在本系列的下一篇文章中,我们将讨论第二组 SQL Server 查询执行计划运算符。敬请关注!

系列目录

SQL Server 执行计划(1) - 概述
SQL Server 执行计划(2) - 如何查看执行计划
SQL Server 执行计划(3) - 如何分析图形执行计划
SQL Server 执行计划(4) - 执行计划运算符详解1
SQL Server 执行计划(5) - 执行计划运算符详解2
SQL Server 执行计划(6) - 执行计划运算符详解3
SQL Server 执行计划(7) - 执行计划运算符详解4
SQL Server 执行计划(8) - 使用执行计划进行查询性能调优
[SQL Server 执行计划(9) - 保存和比较执行计划]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值