在这种情况下将使用哪个索引?

Jon*_*ica 11 sql-server index-tuning sql-server-2014

SQL Server 2014 标准版

我需要找到特定月份往返特定城市的航班数量。例如

select count(*) 
from flights 
where flightTo_AirportCode = 'aaaa' 
and flightFrom_Airportcode = 'bbbb' 
and flightdate < '2016-04-01' 
and flightdate > '2016-02-28' ;
Run Code Online (Sandbox Code Playgroud)

表架构如下。

我试图估计索引模型 A 或索引模型 B(如下)是否更可取(构建索引需要很多小时,并且磁盘空间一次只允许一个存在,所以我试图在跳跃之前查看)。

根据我的经验,任何一个索引都可以。我对吗?

  create index [modelA] on flights (flightTo_AirportCode, flightFrom_AirportCode, flightDate)

  create index [modelB] on flights (flightDate, flightTo_AirportCode, flightFrom_AirportCode)
Run Code Online (Sandbox Code Playgroud)

(或者,更好的是,我可以使用二进制索引或高级机制来解决这个问题吗?)

CREATE TABLE [dbo].[flights](
    [flightId] [uniqueidentifier] NOT NULL,
    [accountId] [uniqueidentifier] NULL,
    [flightDate] [datetime] NULL,
    [flightTo_AirportCode] [nvarchar](30) NULL,
    [flightFrom_AirportCode] [nvarchar](30) NULL,
    -- ... 45 more fields
    CONSTRAINT [PK_flight] PRIMARY KEY CLUSTERED 
(
    [flightId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 70) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

ype*_*eᵀᴹ 18

索引 A 更适合此查询。当WHERE除了IN在列上使用范围条件或运算符的条件之外的所有条件都是相等性检查时,最后一列应该在索引中的最后一列,在所有具有相等性检查的列之后。

这允许优化器使用索引查找匹配条件的第一行,然后遍历索引直到找到不匹配的行。中间的所有行也是匹配的。

因此,此查询的最佳索引是(to, from, date)(您的模型 A)或(from, to, date).

模型 B 索引的日期在前,因此它不是最好的,尽管它仍然是查询的覆盖索引。如果使用它,查询计划将几乎相同。索引寻求找到与范围条件 ( date > '2016-02-28')匹配的第一行,然后遍历索引,直到找到与date < '2016-04-01'. 但是中间的所有行不一定与其他 2 个条件匹配,因此必须根据这些条件检查它们并(可能其中很多)被拒绝。

因此,虽然计划是相似的,但模型 A 计划将只需要通过索引中包含所有需要的行的部分,而模型 B 计划将通过(可能很多)更大的部分指数。


  • 最好对日期 ( YYYYMMDD)使用 100% 安全格式。

  • 如果你想要三月的日期,你应该使用一个包含-不包含的检查:

    AND flightdate >= '20160301' AND flightdate < '20160401' 
    
    Run Code Online (Sandbox Code Playgroud)

    保证使用日期和日期时间类型。您当前的查询还将包括任何'2016-02-28'与时间不同的行'00:00:00'(您能保证没有任何时间吗?),我认为您不想要。inclusive-exclusive 方法也适用于闰年(提醒 2016 年是闰年,因此您的查询也会返回 2 月 29 日的日期)。

另请阅读 Aaron Bertrand 的这些博客文章: