Quel index sera utilisé dans ce scénario?

11

SQL Server 2014 Standard Edition

J'ai besoin de trouver le nombre de vols à destination et en provenance de villes spécifiques pendant certains mois. Par exemple

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

Le schéma du tableau est ci-dessous.

J'essaie d'estimer si le modèle d'index A ou le modèle d'index B (ci-dessous) est préférable (cela prend plusieurs heures pour construire l'index, et l'espace disque ne permet à un seul d'exister à la fois, donc j'essaie de regarder avant de sauter).

D'après mon expérience, l'un ou l'autre indice fera l'affaire. Ai-je raison?

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

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

(Ou, mieux, y a-t-il un index binaire ou un mécanisme avancé que je peux utiliser pour aborder cela?)

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 Reinstate Monica
la source

Réponses:

18

L'index A est meilleur pour cette requête. Lorsque toutes les conditions de la WHEREsont des vérifications d'égalité, sauf une qui utilise une condition de plage ou un INopérateur sur une colonne, cette dernière colonne doit être la dernière de l'index, après toutes les colonnes qui ont une vérification d'égalité.

Cela permet à l'optimiseur d'utiliser une recherche d'index sur la première ligne qui correspond aux conditions, puis de parcourir l'index jusqu'à ce qu'il trouve une ligne qui ne la correspond pas. Toutes les lignes intermédiaires sont également compatibles.

Ainsi, le meilleur index pour cette requête serait soit (to, from, date)(votre modèle A) soit (from, to, date).

L'index du modèle B a la date en premier, ce n'est donc pas le meilleur, bien qu'il s'agisse toujours d'un index de couverture pour la requête. Si cela était utilisé, le plan de requête serait presque le même. Un index cherche à trouver la première ligne qui correspond à la condition de plage ( date > '2016-02-28'), puis traverse l'index jusqu'à ce qu'il trouve une ligne qui ne correspond pas à date < '2016-04-01'. Mais toutes les lignes intermédiaires ne correspondent pas nécessairement aux 2 autres conditions, elles devraient donc être vérifiées par rapport à ces conditions et (peut-être beaucoup d'entre elles) rejetées.

Ainsi, alors que les plans seraient similaires, le plan du modèle A ne devrait parcourir que la partie de l'index qui contient toutes les lignes nécessaires et uniquement celles-ci, tandis que le plan du modèle B passerait par une partie (peut-être beaucoup) plus grande du indice.


  • Il serait également préférable d'utiliser un format 100% sûr pour les dates ( YYYYMMDD).

  • Et si vous voulez les dates en mars, vous devez utiliser un chèque inclusif-exclusif:

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

    Garanti pour fonctionner avec les types date et datetime. Votre requête actuelle inclura également toute ligne qui a '2016-02-28'mais une heure différente de '00:00:00'(pouvez-vous garantir qu'il n'y en a pas?) Dont je suppose que vous ne voulez pas. La méthode inclusive-exclusive fonctionnera également dans les années bissextiles (rappelant que 2016 est une année bissextile, il y avait donc une date du 29 février à laquelle votre requête retournera).

Lisez également ces articles de blog d'Aaron Bertrand:

ypercubeᵀᴹ
la source