Hoo*_*cat 7 performance index sql-server nonclustered-index query-performance
我试图确定为什么 SQL Server 中的查询优化器建议创建一个新索引,而不是使用似乎足以进行查询的现有索引。
首先是桌子。列名已更改以保护无辜者:-)
CREATE TABLE [myTable] (
[id] [int] IDENTITY(1,1) NOT NULL,
[serialNumber] [varchar](12) NOT NULL,
[sName] [varchar](64) NOT NULL,
[meanValue] [int] NOT NULL,
[range] [int] NOT NULL,
[modifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_myTable] PRIMARY KEY CLUSTERED ( [id] ASC )
)
Run Code Online (Sandbox Code Playgroud)
创建有问题的索引:
CREATE NONCLUSTERED INDEX [IDX_myIndex]
ON [myTable] ([serialNumber], [sName], [meanValue], [range])
INCLUDE ([modifiedDate])
Run Code Online (Sandbox Code Playgroud)
添加数据以使用您选择的生成器进行测试;-) 运行以下查询(表只有几百万条记录)
SELECT TOP 1000
[serialNumber],
[sName],
[meanValue],
[range],
[modifiedDate]
FROM [myTable]
WHERE [serialNumber] = 137802
AND [sName] = 'A Name'
Run Code Online (Sandbox Code Playgroud)
查询优化器建议使用新索引,其中额外的 where 子句包含在 INCLUDE 中,而不是键的一部分:
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[myTable] ([sName])
INCLUDE ([serialNumber],[meanValue],[range],[modifiedDate])
Run Code Online (Sandbox Code Playgroud)
我的印象是,只要 WHERE 子句的顺序代表索引列的顺序,就会使用包含更多列的更广泛的索引作为索引。
如果我也在修改数据的 WHERE 上使用索引并且查询优化器不会抱怨:
SELECT TOP 1000
[serialNumber],
[sName],
[meanValue],
[range],
[modifiedDate]
FROM [myTable]
WHERE [serialNumber] = 137802
AND [sName] = 'A Name'
AND ([modifiedDate] >= '2000-04-25' AND [modifiedDate] < '2019-04-30')
Run Code Online (Sandbox Code Playgroud)
DBA 链接
SQL Server 2008R2 - Why is my index not used表明索引键和包含与 SELECT 语句之间更密切的相关性有助于确定索引的使用(但在我的示例中它们基本相同)。我有很多行,这可能满足行使用概率测试,并且没有 NULL - 因此否定了索引的 NULL 效果。
我认为,也许是错误的,索引A, B, C, D
将覆盖查询 where A, B, C
, or A, B
, orA
将运行。这个假设是错误的吗?我意识到可能存在使这个基本概念偏离的边缘条件,但在基本层面上,这不是它应该如何工作的粗略吗?
在此先感谢您的帮助,指出我的愚蠢之处,认识到我需要去(回)DB 学校等...... :-)
ype*_*eᵀᴹ 14
您的索引对于查询来说似乎很好(即覆盖),应该使用它。真正的问题是查询本身,特别是这个隐藏隐式转换的条件:
WHERE [serialNumber] = 137802
Run Code Online (Sandbox Code Playgroud)
根据 SQL Server 的数据类型优先级,当比较两个不同数据类型的值时,将优先级较低的数据类型的值转换为优先级较高的数据类型。不幸的是,int
在列表中高于varchar
. 由于列 ( serialNumber
) 值被转换为整数,因此使用索引的任何希望都破灭了。该列是索引的第一个位置,导致优化器不使用该索引并搜索替代项(以及建议)。
解决方案是不要对WHERE
条件中的列进行任何隐式或显式转换。只需使用:
WHERE [serialNumber] = '137802'
Run Code Online (Sandbox Code Playgroud)