c'è un problema per quando vuoi mettere un OR all'interno di un indice filtrato?


8

c'è un problema per quando vuoi mettere un OR all'interno di un indice filtrato?

create index FIDX_tblbOrders_sdtmOrdCreated_INCL 
on dbo.tblBOrder(sdtmOrdCreated)
INCLUDE (sintMarketID,
         strCurrencyCode,
         sintOrderStatusID
         )
WHERE ((sintMarketId=1)
AND ( (sintOrderStatusId < 9) OR (sintOrderStatusId > 14)))

Sto cercando di creare l'indice sopra, perché NON sono interessato a nessuna situazione in cui sintOrderStatusId IN (9-14)

Ovviamente posso creare una vista o una vista indicizzata, ma stavo cercando di evitarlo.

semplicemente aggiungendo ulteriori informazioni: sintOrderStatusId è un piccolo NOT NOT NULL e i valori possibili vanno da 1 a 30. I 9 a 14 devono essere evitati, quindi l'indice filtrato.

Risposte:


12

Sfortunatamente, non sembra esserci alcun modo per creare un filtro negativo per un indice, senza ricorrere alla creazione di una vista materializzata. Se fosse possibile creare un filtro negativo come quello che desideri, sarebbe molto difficile per la query-ottimizzatore di "raccogliere" l'indice per l'utilizzo, aumentando drasticamente il tempo necessario per trovare un buon piano.

A seconda dei modelli di query per questa tabella, è possibile semplicemente creare due indici; uno per meno di 9 e uno per maggiore di 14. Ognuno di questi indici può essere scelto da Query Optimizer per WHEREclausole semplici comeWHERE StatusID = 6

CREATE TABLE dbo.TestNegativeFilter
(
    TestNegativeFilter INT NOT NULL
        CONSTRAINT PK_TestNegativeFilter
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , StatusID INT NOT NULL
);
GO

CREATE INDEX IX_TestNagativeFilter_LessThan9
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID < 9);

CREATE INDEX IX_TestNagativeFilter_GreaterThan14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID > 14);

Un altro modo per ottenere questo risultato potrebbe essere:

CREATE INDEX IX_TestNegativeFilter_9_to_14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID IN (9, 10, 11, 12, 13, 14));

SELECT *
FROM dbo.TestNegativeFilter tnf
EXCEPT
SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID IN (9, 10, 11, 12, 13, 14);

Questo utilizza l'indice filtrato da 9 a 14 per escludere le righe.

Sul mio banco di prova, un semplice indice di copertura restituisce le righe di gran lunga il più veloce:

CREATE NONCLUSTERED INDEX IX_TestNegativeFilter_StatusID
ON dbo.TestNegativeFilter(StatusID)
INCLUDE (TestNegativeFilter);

SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID NOT IN (9, 10, 11, 12, 13, 14);

In alternativa, usando una variazione dell'approccio usato nella tua risposta :

CREATE INDEX [IX dbo.TestNegativeFilter StatusID not 9-14]
ON dbo.TestNegativeFilter (StatusID)
WHERE StatusID <> 9
AND StatusID <> 10
AND StatusID <> 11
AND StatusID <> 12
AND StatusID <> 13
AND StatusID <> 14;

Nonostante il filtro sia scritto come congiunzioni, supporta le query scritte in uno dei seguenti modi (il primo è leggermente più efficiente):

  • StatusID NOT IN (9, 10, 11, 12, 13, 14)
  • StatusID < 9 OR StatusID > 14
  • StatusID NOT BETWEEN 9 AND 14

1

non eccezionale, ma sembra funzionare:

create index FIDX_tblbOrders_sdtmOrdCreated_INCL 
on dbo.tblBOrder(sdtmOrdCreated)
INCLUDE (sintMarketID,
         strCurrencyCode,
         sintOrderStatusID
         )
WHERE ((sintMarketId=1)
AND ( sintOrderStatusId IN (0,1,2,3,4,5,6,7,8,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)))

Quando provo a farlo in un modo migliore, non mi piace:

inserisci qui la descrizione dell'immagine


1
Secondo la documentazione MSND: "Gli indici filtrati sono definiti su una tabella e supportano solo operatori di confronto semplici. Se è necessaria un'espressione di filtro che fa riferimento a più tabelle o ha una logica complessa, è necessario creare una vista". msdn.microsoft.com/en-us/library/cc280372.aspx
Paweł Tajs
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.