Какой индекс будет использоваться в этом сценарии?

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 или index modelB (ниже) предпочтительным (создание индекса занимает много часов, а дисковое пространство позволяет существовать только одному за раз, поэтому я пытаюсь посмотреть, прежде чем прыгнуть).

Исходя из моего опыта, подойдет любой индекс. Я прав?

  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]
Jonesome Восстановить Монику
источник

Ответы:

18

Индекс А лучше для этого запроса. Когда все условия в WHEREявляются проверками на равенство, кроме одного, которое использует условие диапазона или INоператор для столбца, тогда этот последний столбец должен быть последним в индексе после всех столбцов, которые имеют проверку на равенство.

Это позволяет оптимизатору использовать поиск индекса по первой строке, соответствующей условиям, и затем перемещаться по индексу, пока не найдет строку, не соответствующую ему. Все строки между ними тоже совпадают.

Таким образом, лучшим индексом для этого запроса будет (to, from, date)(ваша модель A) или (from, to, date).

Индекс модели B сначала имеет дату, поэтому он не самый лучший, хотя он все еще является индексом покрытия для запроса. Если бы это использовалось, план запроса был бы почти таким же. Индекс ищет первую строку, которая соответствует условию диапазона ( date > '2016-02-28'), а затем пересекает индекс, пока не найдет строку, которая не соответствует date < '2016-04-01'. Но все промежуточные строки не обязательно соответствуют двум другим условиям, поэтому их необходимо проверить на соответствие этим условиям и (возможно, многие из них) отклонить.

Таким образом, хотя планы будут схожими, план модели А должен проходить только ту часть индекса, которая содержит все необходимые строки и только их, в то время как план модели Б будет проходить (возможно, намного) большую часть показатель.


  • Также было бы лучше использовать 100% безопасный формат для дат ( YYYYMMDD).

  • И если вы хотите, чтобы даты были в марте, вы должны использовать инклюзивный чек:

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

    Гарантированно работает с типами date и datetime. Ваш текущий запрос будет также включать в себя любую строку, в которой '2016-02-28'время отличается от времени '00:00:00'(можете ли вы гарантировать, что его нет?), Которое, я полагаю, вам не нужно. Инклюзивный-эксклюзивный метод также будет работать в високосные годы (напоминая, что 2016 год - високосный, поэтому также была дата 29 февраля, которую ваш запрос будет возвращать).

Прочитайте также эти сообщения в блоге Аарона Бертрана:

ypercubeᵀᴹ
источник