[英]Why doesn't this query use the proper index?
表定义:
CREATE TABLE [dbo].[AllErrors](
[ID] [int] IDENTITY(1,1) NOT NULL,
[DomainLogin] [nvarchar](50) NULL,
[ExceptionDate] [datetime] NULL,
[ExceptionDescr] [nvarchar](max) NULL,
[MarketName] [nvarchar](50) NULL,
[Version] [nvarchar](50) NULL,
CONSTRAINT [PK_AllErrors] PRIMARY KEY CLUSTERED ([ID] ASC)
)
-- Add an index on the date
CREATE NONCLUSTERED INDEX [IX_ExceptionDate] ON [dbo].[AllErrors] ([ExceptionDate] ASC)
我运行这个查询:
declare @yesterday datetime
select @yesterday = getdate() - 1
SELECT * INTO #yst
from AllErrors
where ExceptionDate between @yesterday and @yesterday + 1
此代码不使用我的IX_ExceptionDate
(从执行计划中收集)。 它对主键索引执行群集扫描。 但是,下面的代码确实使用了IX_ExceptionDate
索引:
SELECT * INTO #yst
from AllErrors
where ExceptionDate between @yesterday and @yesterday + 1
AND ExceptionDate = ExceptionDate
为什么是这样?
编辑:添加了视觉执行计划。
编辑:下面的文本执行计划。
查询1:
| - 表格插入(OBJECT:([#yst]),SET :( [#yst]。[ID] = [Expr1006],[#yst]。[DomainLogin] = [MarketStats]。[dbo]。[AllErrors ]。[DomainLogin],[#yst]。[ExceptionDate] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate],[#yst]。[ExceptionDescr] = [MarketStats]。[dbo]。[AllErrors ]。[ExceptionDescr],[#yst]。[MarketName] = [MarketStats]。[dbo]。[AllErrors]。[MarketName],[#yst]。[Version] = [MarketStats]。[dbo]。[AllErrors ]。[Version]))| - Top(ROWCOUNT est 0)| - 计算标量(DEFINE :( [Expr1006] = setidentity([MarketStats]。[dbo]。[AllErrors]。[ID],( - 7 ),(0),N'#yst')))| - 聚集索引扫描(OBJECT:([MarketStats]。[dbo]。[AllErrors]。[PK_AllErrors]),WHERE:([MarketStats]。[dbo] ]。[AllErrors]。[ExceptionDate]> = [@昨天] AND [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate] <= [@ yesterday] +'1900-01-02 00:00:00.000' ))
查询2:
| - 表格插入(OBJECT:([#yst]),SET :( [#yst]。[ID] = [Expr1006],[#yst]。[DomainLogin] = [MarketStats]。[dbo]。[AllErrors ]。[DomainLogin],[#yst]。[ExceptionDate] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate],[#yst]。[ExceptionDescr] = [MarketStats]。[dbo]。[AllErrors ]。[ExceptionDescr],[#yst]。[MarketName] = [MarketStats]。[dbo]。[AllErrors]。[MarketName],[#yst]。[Version] = [MarketStats]。[dbo]。[AllErrors ]。[Version]))| - Top(ROWCOUNT est 0)| - 计算标量(DEFINE :( [Expr1006] = setidentity([MarketStats]。[dbo]。[AllErrors]。[ID],( - 7 ),(0),N'#yst')))| - 嵌套循环(内部连接,外部参考:([MarketStats]。[dbo]。[AllErrors]。[ID],[Expr1008])优化为UNORDERED PREFETCH)| - 索引查询(OBJECT:([MarketStats]。[dbo]。[AllErrors]。[IX_ExceptionDate]),SEEK:([MarketStats]。[dbo]。[AllErrors]。[ExceptionDate]> = [@昨天]和[MarketStats]。[dbo]。[AllErrors]。[ExceptionDate] <= [@yesterday] +'1900-01-02 00:00:00.000'),其中:([MarketStats]。[dbo]。 [AllErrors]。[ExceptionDate] = [MarketStats]。[DBO]。[AllErrors]。[E xceptionDate])ORDERED FORWARD)| - 集群索引查询(OBJECT:([MarketStats]。[dbo]。[AllErrors]。[PK_AllErrors]),SEEK:([MarketStats]。[dbo]。[AllErrors]。[ID ] = [MarketStats]。[dbo]。[AllErrors]。[ID])LOOKUP ORDERED FORWARD)
在编译查询时,它不知道变量的值是什么。 你可以试试OPTION (RECOMPILE)
。
我认为在查询中添加AND
子句(即使在逻辑上它使它不再具有选择性)必须误导优化器以更高的选择性估计查询,从而为您提供所需的计划!
您在评论中说没有ExceptionDate = ExceptionDate
的版本估计为88234.8
行,版本为8823.48
通常,在没有可用统计信息的情况下,SQL Server会根据谓词中比较运算符的类型回退到启发式算法。
它假定>
谓词将返回30%的行,例如,a =
谓词将返回10%的行,因此看起来它只是直接将其应用于第一次估计的结果。 有趣的是,它没有考虑到这里的等于对立柱本身的事实!
简短回答:由于“SELECT *”,您的查询会遇到聚簇索引:Key Lookup操作比聚簇索引扫描要昂贵得多。
查看由此产生的不同查询计划
declare @yesterday datetime
select @yesterday = getdate() - 1
SELECT * INTO dbo.#yst
from AllErrors WITH (INDEX = IX_ExceptionDate)
where ExceptionDate between @yesterday and @yesterday + 1
和
declare @yesterday datetime
select @yesterday = getdate() - 1
SELECT * INTO dbo.#yst
from AllErrors
where ExceptionDate between @yesterday and @yesterday + 1
和
declare @yesterday datetime
select @yesterday = getdate() - 1
SELECT ExceptionDate INTO dbo.#yst
from AllErrors
where ExceptionDate between @yesterday and @yesterday + 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.