在群集索引上排序时未使用SQL Server 2016非聚簇索引

问题描述 投票:1回答:1

您能否向我解释为什么在查询聚簇索引时查询时未使用此非聚簇索引?

CREATE TABLE [dbo].[table]
(
    [NPId] [BIGINT] IDENTITY(1,1) NOT NULL, 
    [RequestDate] [DATETIME2](2) NOT NULL,
    [Status] [TINYINT] NOT NULL,
    [StatusCodeId] [SMALLINT] NULL,
    [NumberCount] [INT] NULL,
    [Number] [BIGINT] NULL,

    CONSTRAINT [PK_NPLog_1] 
       PRIMARY KEY CLUSTERED ([NPId] ASC)
               WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                     IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                     ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_ReqDate] 
ON [dbo].[table] ([RequestDate] ASC)
INCLUDE ([NPId])

查询:

DECLARE @date datetime2(2) = '2018.07.10'
DECLARE @date2 datetime2(2) = '2018.08.10'

SELECT TOP 10 npl.NPId 
FROM [table] npl  
WHERE npl.RequestDate >= @date 
  AND npl.RequestDate < @date2 
ORDER BY npid

如果我在requestDate上设置顺序,则使用index。

sql-server indexing b-tree
1个回答
1
投票

这很容易重现。

只需将以下虚拟数据插入到您问题中的表格中......

insert into [dbo].[table]
SELECT TOP 1000000 DATEADD(SECOND,  CRYPT_GEN_RANDOM(4)% 1000000,GETDATE()) , 1, 1, 1, 1
FROM sys.all_objects o1, sys.all_objects o2

然后跑

DECLARE @date datetime2(2) = '2018.07.10'
DECLARE @date2 datetime2(2) = '2018.08.10'

SELECT TOP 10 npl.NPId 
FROM [table] npl  
WHERE npl.RequestDate >= @date 
  AND npl.RequestDate < @date2 
ORDER BY npid
OPTION (QUERYTRACEON 9130) /*so filter visible in the plan*/


SELECT TOP 10 npl.NPId 
FROM [table] npl  WITH (INDEX = IX_ReqDate) 
WHERE npl.RequestDate >= @date 
  AND npl.RequestDate < @date2 
ORDER BY npid

enter image description here

以上是使用CardinalityEstimationModelVersion = 140 - 类似的将在CE的其他版本中看到,虽然确切的数字可能是不同的。

  1. 数据范围中使用的值隐藏在变量中,因此SQL Server假定它将匹配16.431676725155%行(0.30*SQRT(0.30))。
  2. SQL Server还假定这些行将在整个表中均匀分布。所以它假设它需要在得到10与谓词匹配之前读取60.8581(10/(0.30*SQRT(0.30)))。
  3. 对于另一个计划,它假设它需要对表格的16.4%进行排序,这会花费大得多。

您可以尝试添加OPTION (RECOMPILE),以便SQL Server嗅探变量使用的日期范围,并且可以将16.4%的估计值降低到足以更改计划。

但是,可能更有可能的是,估计值会降低但不足以更改计划,CI计划仍然不足(因为匹配范围的行不会在整个表中均匀分布,并且必须读取的行数多于估计值)。在这种情况下,您可以考虑使用索引提示来获取所需的索引。

© www.soinside.com 2019 - 2024. All rights reserved.