You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何WHERE Salary > 0条件未引发表扫描或索引扫描?

问题解答:为什么带WHERE Salary>0的查询未触发扫描?

先还原你的测试代码:

CREATE DATABASE QueryTest
GO
USE QueryTest
CREATE TABLE Person (
 ID INT IDENTITY (1,1),
 FirstName NVARCHAR(50),
 SurName NVARCHAR(50),
 Salary MONEY
)
INSERT INTO Person SELECT TOP 2000 FirstName, LastName, RAND(CAST( NEWID() AS varbinary)) *100000 FROM [AdventureWorks2014].[Person].[Person] ORDER BY NEWID()
CREATE INDEX IX_Person_Salary ON Person ( Salary )

你的疑问是:执行SELECT Salary FROM Person时触发了表扫描,但SELECT Salary FROM Person WHERE Salary > 0却没有触发表扫描或索引扫描,这是为什么?


核心原因:SQL Server优化器的索引逻辑差异

让我们一步步拆解两个查询的执行计划选择:

1. 无WHERE条件的SELECT Salary FROM Person

你的Person表是一个堆(因为没有显式创建聚集索引,SQL Server默认会将无聚集索引的表作为堆存储)。此时优化器需要在两种读取方式中选最优:

  • 选项1:堆扫描(也就是你看到的表扫描):直接读取堆的所有数据页面,提取Salary列。
  • 选项2:非聚集索引扫描:读取IX_Person_Salary的所有索引页面,提取Salary列。

由于你的表只有2000行,堆的页面数量极少,优化器判断堆扫描的IO成本更低,所以选择了表扫描。

2. 带WHERE Salary > 0的查询

这里有两个关键逻辑决定了执行计划的差异:

  • 统计信息的判断:SQL Server在创建索引时会生成Salary列的统计信息,发现你插入的所有Salary值都大于0(RAND()生成0到1之间的随机数,乘以100000后结果必然>0)。这意味着WHERE Salary > 0是一个恒真条件,会匹配表中所有行。
  • 覆盖索引与索引seek:你的查询只需要Salary列,而IX_Person_Salary是一个覆盖索引(查询所需的所有列都包含在索引中)。此时优化器会选择使用索引seek:因为索引是按Salary有序存储的,优化器可以快速定位到Salary>0的起始位置(即索引第一行),然后读取所有后续行。这种操作在执行计划中显示为索引seek,而非扫描——这就是你看到“未引发表扫描或索引扫描”的原因。

简单来说,虽然两个查询最终都返回所有行,但优化器根据查询条件的存在,选择了更高效的索引seek来利用覆盖索引,而非表扫描或索引扫描。


内容的提问来源于stack exchange,提问作者dualcoredba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:12:57