1

我正在处理一个非常大的表(每天添加大约 270 万行),它具有以下结构:

CREATE TABLE [dbo].[Result](
    [ResultDate] [date] NOT NULL,
    [Thing1Id] [int] NOT NULL,
    [Num] [int] NOT NULL,
    [Thing2Id] [int] NOT NULL,
CONSTRAINT [PK_Result] PRIMARY KEY CLUSTERED 
(
    [ResultDate] ASC,
    [Thing1Id] ASC,
    [Num] ASC
))

由于集群主键位于 ResultDate、Thing1Id 和 Num 上,我希望以下查询是最佳的:

SELECT Thing2.* 
FROM dbo.Result
INNER JOIN Thing2 ON Thing2.Id = result.Thing2Id
WHERE 
    ResultDate >= '2012-01-01'
    AND
    ResultDate <= '2012-01-30'
    AND Thing1Id = 23

如您所见,查询在 1 月 12 日查找特定 Thing1 的结果。

但是,执行计划表明,通过添加以下索引可以获得巨大的性能提升:

CREATE NONCLUSTERED INDEX [IX_Missing]
ON [dbo].[Result] ([Thing1Id],[ResultDate])
INCLUDE ([Num],[Thing2Id]) 

可以肯定的是,添加此索引确实会大大提高性能。

有人可以解释为什么吗?就我而言,应该使用聚集主键充分缩小结果范围,添加它会使索引大小变得更大并增加不必要的开销。

我可以对表进行不同的索引以获得更好的性能吗?

(请注意,实际上该表实际上是合并的 2 个表,数据每天从一个表转移到另一个表,并且每月对数据进行分区)。

4

3 回答 3

0

索引基本上按“键”排列您的表格。在你的情况下'thing1ID','ResultDate'。对表进行排序后,访问行比遍历整个表(270 万)要快得多,因为您不知道行可能在哪里。

即2,7,3,8,1,您需要搜索整个表格才能找到数字1。但是如果您有1、2、3、7、8。您只检查第一个数字。

但!对于包含许多涉及“键”的更新/插入的表,速度会变慢,因为您需要在每个条目后对表进行排序。因此,找出最适合您的数据库的方法。

于 2012-12-05T10:59:00.713 回答
0

PK 不是您的查询的最佳选择,因为您正在对 ResultDate 进行范围搜索。通过您的查询,您可以将 Thing1Id 23 的搜索范围缩小到大约。8100 万行仍然很多。

在您的查询中,对 Thing1Id 的搜索固定为 23,因此 Thing1Id 和 ResultDate 上的额外索引将最适合您的查询。

于 2012-12-05T11:36:26.340 回答
0

查询执行计划会确切地告诉您这里发生了什么,这通常比推测要好得多,但是在这种情况下,我认为有足够的信息可以进行有根据的猜测。

首先,INCLUDE ([Num],[Thing2Id])索引的一部分只是意味着这两列的值在索引以及表本身中是重复的。它很有用,因为它可以防止 SQL Server 在该索引中执行查找(在这种情况下索引是覆盖索引)之后必须在表本身中查找这些详细信息,但是通常这种查找非常快,因此不太可能直接负责“大幅”提高性能。我猜下面的指数是 99.9% 一样快。

CREATE NONCLUSTERED INDEX [IX_Missing]
ON [dbo].[Result]
(
    [Thing1Id],
    [ResultDate]
)

在我们继续之前,重要的是要了解 SQL Server 执行此查询有两种方法(为了解释的目的,已大大简化):

  1. 查找ResultDate在两个提供的日期之间的所有行,然后在这些行中查找 aThing1Id为 23的行
  2. 查找 aThing1Id为 23 的所有行,然后在这些行中查找ResultDate在两个提供的日期之间的行

根据表中存在的数据,其中一种方法可能另一种方法快得多,例如,如果表中的大多数行具有Thing1Id23 并且很少有匹配ResultDate,那么它可能会更快使用第一种方法,因为它可以更快地消除更多行。

我们需要了解的另一个重要难题是,由于索引的工作方式,SQL 不能在第二种情况下使用您的聚集索引,因为Thing1Id列在列之后ResultDate(这有点像要求某人使用书中的索引找到第二个字母是“Q”的所有条目,然后要求他们通过并只挑选那些以“S”开头的单词)


因此,我对为什么这个索引提高性能的猜测仅仅是 SQL Server 使用方法 2(Thing1Id首先过滤)比方法 1 更有效。

您应该能够使用查询执行计划来确认这一点。

于 2013-06-04T14:52:01.860 回答