このシナリオではどのインデックスが使用されますか?


11

SQL Server 2014 Standard Edition

特定の都市を発着する特定の月のフライト数を調べる必要があります。例えば

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

テーブルスキーマは次のとおりです。

インデックスmodelAまたはインデックスmodelB(下記)が望ましいかどうかを推定しようとしています(インデックスの作成には何時間もかかり、ディスクスペースでは一度に1つしか存在できないため、跳躍する前に調べます)。

私の経験では、どちらのインデックスでも十分です。私は正しいですか?

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

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

(または、より良い、これに取り組むために使用できるバイナリインデックスまたは高度なメカニズムはありますか?)

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]

回答:


18

このクエリにはインデックスAが適しています。列のWHERE範囲条件またはIN演算子を使用しているものを除いて、すべての条件が等価チェックである場合、その最後の列は、等価チェックを持つすべての列の後に、インデックスの最後でなければなりません。

これにより、オプティマイザは条件に一致する最初の行にインデックスシークを使用し、一致しない行が見つかるまでインデックスを走査できます。その間のすべての行も一致します。

したがって、このクエリに最適なインデックスは(to, from, date)(モデルA)またはのいずれか(from, to, date)です。

モデルBのインデックスは日付が最初であるため、クエリのカバーインデックスですが、最適ではありません。これを使用した場合、クエリプランはほぼ同じになります。インデックスは、範囲条件(date > '2016-02-28')に一致する最初の行を探し、次にに一致しない行が見つかるまでインデックスを走査しますdate < '2016-04-01'。ただし、その間のすべての行が他の2つの条件と必ずしも一致するわけではないため、これらの条件をこれらの条件に対してチェックし、(おそらくそれらの多くは)拒否する必要があります。

したがって、プランは似ていますが、モデルAのプランは、必要なすべての行とそれらのみを含むインデックスの部分のみを通過する必要がありますが、モデルBのプランは、(おそらくはるかに)大きい部分を通過します。インデックス。


  • また、日付には100%安全な形式を使用することをお勧めします(YYYYMMDD)。

  • 3月の日付が必要な場合は、包括的および排他的チェックを使用する必要があります。

    AND flightdate >= '20160301' AND flightdate < '20160401' 

    日付型と日時型での動作が保証されています。現在のクエリには'2016-02-28'、時間は異なるが'00:00:00'(ないことを保証できますか?)時間が異なる行も含まれます。インクルーシブとエクスクルーシブの方法は、うるう年でも機能します(2016年はうるう年であるため、クエリが返す2月29日の日付もありました)。

Aaron Bertrandによる以下のブログ投稿もお読みください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.