Quale indice verrà utilizzato in questo scenario?


11

SQL Server 2014 Standard Edition

Devo trovare il numero di voli da e per città specifiche per determinati mesi. Per esempio

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

Lo schema della tabella è di seguito.

Sto cercando di stimare se è preferibile il modello di indice A o il modello di indice B (di seguito) (ci vogliono molte ore per costruire l'indice e lo spazio su disco consente di esistere solo uno alla volta, quindi sto cercando di guardare prima di saltare).

Dalla mia esperienza, entrambi gli indici lo faranno. Ho ragione?

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

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

(O meglio, c'è un indice binario o un meccanismo avanzato che posso usare per avvicinarmi a questo?)

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]

Risposte:


18

L'indice A è migliore per questa query. Quando tutte le condizioni in WHEREsono controlli di uguaglianza tranne uno che utilizza una condizione di intervallo o un INoperatore su una colonna, quest'ultima colonna dovrebbe essere l'ultima nell'indice, dopo tutte le colonne che hanno un controllo di uguaglianza.

Ciò consente all'ottimizzatore di utilizzare un indice di ricerca nella prima riga che soddisfa le condizioni e quindi attraversare l'indice fino a quando non trova una riga che non corrisponde. Anche tutte le righe in mezzo sono una corrispondenza.

Quindi, l'indice migliore per questa query sarebbe (to, from, date)(il tuo modello A) o (from, to, date).

L'indice del modello B ha prima la data, quindi non è il migliore, sebbene sia ancora un indice di copertura per la query. Se fosse utilizzato, il piano di query sarebbe quasi lo stesso. Un indice cerca di trovare la prima riga che corrisponde alla condizione dell'intervallo ( date > '2016-02-28') e quindi attraversa l'indice fino a quando non trova una riga che non corrisponde a date < '2016-04-01'. Ma tutte le righe intermedie non corrispondono necessariamente alle altre 2 condizioni, quindi dovrebbero essere verificate rispetto a queste condizioni e (possibilmente molte di esse) respinte.

Quindi, mentre i piani sarebbero simili, il piano del modello A dovrebbe passare solo attraverso la parte dell'indice che ha tutte le righe necessarie e solo loro, mentre il piano del modello B attraverserebbe una parte (forse molto) più grande del indice.


  • Sarebbe anche meglio usare un formato sicuro al 100% per le date ( YYYYMMDD).

  • E se desideri le date a marzo, dovresti utilizzare un controllo inclusivo esclusivo:

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

    Garantito per funzionare con tipi di data e data. La tua query corrente includerà anche qualsiasi riga che ha '2016-02-28'ma un tempo diverso da '00:00:00'(puoi garantire che non ce ne sia?) Che presumo non voglia. Il metodo inclusivo funzionerà anche negli anni bisestili (ricordando che il 2016 è un anno bisestile, quindi c'era anche una data del 29 febbraio a cui restituirà la query).

Leggi anche questi post sul blog di Aaron Bertrand:

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.