为什么要排序非聚簇索引字段?

时间:2014-01-11 01:06:34

标签: sql-server

假设我有一张包含ID,名称和日期的表格。

我有一个非聚集索引,如

CREATE NONCLUSTERED INDEX IX_Test_NameDate ON [dbo].[Test] (Name, Date)

当我运行查询时,

select 
    [Name], [Date]
from 
    [dbo].[Test] WITH (INDEX(IX_Test_NameDate))
where 
    [Name] like 'A%'
order by 
    [Date] asc

我参与了SQL Server的执行计划,

Select <-- Sort <-- Index Seek (NonClustered)

为什么排序?日期是否已在非聚集索引中排序?什么是更好的非聚集索引看起来不需要排序(只有索引搜索)。

(不能使用聚簇索引,因为此示例是具有多行/索引的更大示例的精简版本。)

例如,我得到了一个类似于

的表的执行计划(带排序)
ID  Name    Date 
 1    A     2014-01-01 
 2    A     2014-02-01
 3    A     2014-03-01
 4    A     2014-04-01
 5    B     2014-01-01
 6    B     2014-02-01
 7    B     2014-03-01
 8    B     2014-04-01
 9    B     2014-05-01
10    B     2014-06-01

在这种情况下,日期不应该排序吗?

1 个答案:

答案 0 :(得分:2)

不,Date列不是“已经在非聚集索引中排序”,至少不是本身。它在 Name之后排序。

考虑以下简单的表格数据:

Name     Date
-----    --------
Allen    1/1/2014
Barb     1/1/2013
Charlie  1/1/2015
Darlene  1/1/2012
Ernie    1/1/2016
Faith    1/1/2011

Name排序后,Date列可能会出现故障。保证日期仅适用于具有相同Name的行。

你的目标是彼此交叉的目的。您需要多个名称 - 因此数据最好按名称排序,以便可以进行搜索,但是您希望按日期排序。您如何建议存储上面的六行表,以便按日期对每个可能的名称范围进行排序?

如果有关于名称范围的某种规律性或模式(例如,您始终仅按首字母拉取名称),则可能存在解决方法。

ALTER TABLE dbo.Test ADD NamePrefix AS (Left(Name, 1)) PERSISTED;
CREATE NONCLUSTERED INDEX IX_Test_NamePrefix_Date ON dbo.Test (NamePrefix, Date);

现在这个查询理论上不需要执行排序:

SELECT Name, Date
FROM dbo.Test
WHERE NamePrefix = 'A'
ORDER BY Date;

请注意,添加像这样的持久计算列有一些可能的问题:增加数据大小,这种设计在几乎所有情况下几乎肯定都是错误的,计算列的扩散会非常糟糕,等等。

P.S。通常不是手动强制索引的最佳做法 - 让优化程序选择。