我有一个关于SQL Server索引的问题。我不是DBA,认为对于那些是DBA的人来说答案是很清楚的。我正在使用SQL Server 2008。
我有一个类似于以下表格的表格(但有更多列):
CREATE TABLE [dbo].[Results](
[ResultID] [int] IDENTITY(1,1) NOT NULL,
[TypeID] [int] NOT NULL,
[ItemID] [int] NOT NULL,
[QueryTime] [datetime] NOT NULL,
[ResultTypeID] [int] NOT NULL,
[QueryDay] AS (datepart(day,[querytime])) PERSISTED,
[QueryMonth] AS (datepart(month,[querytime])) PERSISTED,
[QueryYear] AS (datepart(year,[querytime])) PERSISTED,
CONSTRAINT [PK_Results] PRIMARY KEY CLUSTERED
(
[ResultID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
重要的字段是ResultID,它是主键,以及QueryTime,表示产生结果的日期时间。
此外,我还有以下索引(还有其他索引):
CREATE NONCLUSTERED INDEX [IDX_ResultDate] ON [dbo].[Results]
(
[QueryTime] ASC
)
INCLUDE ( [ResultID],
[ItemID],
[TypeID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
在一个拥有约一百万行数据的数据库中,当执行以下查询时会使用索引:
select top 1 * from results where querytime>'2009-05-01' order by ResultID asc
在同一数据库的另一个实例中,有5000万行数据,SQL Server决定不使用索引,而是进行聚集索引扫描,结果速度非常慢(并且速度取决于日期)。即使我使用查询提示让它使用IDX_ResultDate,它仍然有些慢,并且它花费94%的时间通过ResultID进行排序。我发现通过创建一个具有ResultID和QueryTime作为排序列的索引,可以加快我的查询速度。
因此,我创建了以下内容:
CREATE NONCLUSTERED INDEX [IDX_ResultDate2] ON [dbo].[Results]
(
[QueryTime] ASC,
[ResultID] ASC
)
INCLUDE ( [ItemID],
[TypeID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
我原以为它会先使用按查询时间排序的方式来查找匹配结果,这些结果已经按结果ID排序。然而,实际情况并非如此,因为这个索引对现有索引的性能没有任何改变。
接着,我尝试了以下索引:
CREATE NONCLUSTERED INDEX [IDX_ResultDate3] ON [dbo].[Results]
(
[ResultID] ASC,
[QueryTime] ASC
)
INCLUDE ( [ItemID],
[TypeID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
这个函数可以产生预期的结果。它似乎在常数时间内返回(不到一秒钟)。
然而,我对于为什么IDX_ResultDate3有效而IDX_ResultDate2无效感到困惑。
我会认为,在已排序的QueryTime列表中进行二分查找,然后查看其ResultIDs子列表中的第一个结果是最快的方法来获取结果。(因此我的初始排序顺序)
附加问题:我应该创建一个包含QueryTime日期部分的持久化列,并在该列上建立索引吗?(正如您在上面看到的,我已经有三个持久化列)