Qual è l'effetto della sostituzione di indici con indici filtrati (valore non nullo)?


10

Il nostro progetto gestisce un database molto grande e molto complicato. Quindi circa un mese fa, abbiamo notato che lo spazio utilizzato dalle colonne indicizzate contenenti valori null stava diventando troppo grande. In risposta a ciò, ho scritto come script che avrebbe cercato dinamicamente tutti gli indici a colonna singola contenenti più dell'1% di valori null, quindi eliminandoli e ricrearli come indici filtrati a condizione che il valore NON fosse NULL. Ciò eliminerebbe e ricreare centinaia di indici in tutto il database e in genere libererebbe quasi il 15% dello spazio utilizzato dall'intero DB.

Ora ho due domande su questo:

A) Quali sono gli svantaggi dell'utilizzo di indici filtrati in questo modo? Suppongo che migliorerebbe solo le prestazioni, ma ci sono rischi per le prestazioni?

B) Abbiamo ricevuto errori ( "non è possibile eliminare l'indice XYZ perché non esiste o non si dispone dell'autorizzazione" ) quando si rilasciano e si ricreano gli indici, anche se dopo il controllo tutto è andato esattamente come previsto. Come può succedere?

Grazie per qualsiasi aiuto!

Modifica: in risposta a @Thomas Kejser

Ciao e grazie, ma risulta che questo è stato un disastro. All'epoca non capivamo diverse cose come:

  1. Durante una query, SQLOS crea piani di indice prima di determinare che non può utilizzare i valori NULL per unire le colonne della tabella. Ad esempio, è davvero necessario disporre di un filtro della clausola WHERE adatto all'indice per ogni indice filtrato utilizzato nella query, altrimenti l'indice non verrà utilizzato affatto.
  2. Eliminare e creare indici e aggiornare in modo ridondante le loro statistiche ancora una volta in seguito potrebbe non essere ancora sufficiente per produrre i piani aggiornati, che abbiamo supposto avrebbero fatto. Sembra che in alcuni casi solo un carico di lavoro abbastanza elevato costringerà SQL Server a rivalutare i piani.
  3. Esistono alcuni aspetti esotici della funzionalità del pianificatore di esecuzione che sono difficili da determinare solo attraverso il buon senso e la logica. Con migliaia di variazioni generate da code-based di diverse query anche, indici apparentemente inutili possono aiutare in alcune statistiche e piani di query che finiscono per essere utilizzati in query critiche.

Alla fine, questi cambiamenti sono stati ripristinati. Quindi gli indici filtrati sono uno strumento potente, ma è necessario capire veramente quali dati vengono recuperati da quelle colonne. Laddove gli indici normali a parte i problemi di spazio sono piuttosto facili da applicare, gli indici filtrati rappresentano soluzioni molto personalizzate. Non sono certamente un sostituto per un indice regolare, piuttosto un'estensione ad essi in quelle circostanze particolari che sono richieste.


Potresti voler riesaminare anche la tua strategia di indicizzazione. Se hai centinaia di indici a campo singolo, probabilmente non è ottimale.
JNK,

La necessità di questi deriva dal fatto che il database è parzialmente ereditato da un altro sistema. Per impostazione predefinita, abbiamo alcune tabelle astratte e diverse colonne astratte che potrebbero non essere utilizzate affatto, il che produce la maggior parte di queste enormi quantità di valori NULL indicizzati. Per quanto riguarda gli indici a campo singolo, vengono creati dal requisito di base che ogni chiave esterna deve essere indicizzata e molti di questi si trovano in queste colonne che contengono principalmente o solo valori NULL.
Kahn,

Risposte:


8

Approccio molto interessante. Il mio voto per la creatività.

Da quando hai recuperato lo spazio, suppongo che gli indici originali non siano più a posto? Gli svantaggi degli indici filtrati sono quindi:

In termini pratici, ciò significa che è necessario fare molta attenzione con gli indici filtrati poiché spesso si tradurranno in piani di query orribili. Non vorrei andare fino a chiamarli inutili, ma li vedo come un'aggiunta agli indici tradizionali, non come un rimpiazzo (come stai cercando di fare).


"La parametrizzazione delle query non funziona con gli indici filtrati". questo può probabilmente essere risolto con l'opzione (ricompilare)
MichaelD

2

Thomas Kejser risponde a questo argomento molto sopra.

Ho appena pensato di aggiungere 2 centesimi.

Ho visto alcuni indici filtrati usati solo (mostrati nel piano di esecuzione) quando corrispondi esattamente alla clausola where nella tua query come dove nell'indice filtrato.

hai provato a usare le viste indicizzate ? colonne sparse ?

Credo che per quanto riguarda solo i giunti interni, è possibile creare una vista indicizzata contenente le clausole where degli indici filtrati e quindi utilizzare invece la vista.

Potrebbe esserci più di una vista. Ma come per gli indici non cluster, troppi rallenteranno la tua scrittura.

Nella mia esperienza avresti avuto buoni guadagni nella lettura ma avresti dovuto monitorare le scritture (inserimenti e aggiornamenti) specialmente se le tabelle sono coinvolte nella replica.

Tuttavia, poiché capisco che la tua preoccupazione principale è the null valuesquindi, ti suggerirei colonne SPARSE nei tuoi indici .

Le colonne sparse sono particolarmente appropriate per gli indici filtrati

Dato che ho pubblicizzato colonne sparse, non mi sentirei bene se non ti parlassi anche dei suoi limiti:

Quando si progettano tabelle con colonne sparse, tenere presente che sono necessari altri 2 byte di sovraccarico per ogni colonna sparsa non nulla nella tabella durante l'aggiornamento di una riga.

Come risultato di questo

requisito di memoria aggiuntivo, gli aggiornamenti possono non riuscire in modo imprevisto con errore 576 quando la dimensione totale della riga, incluso questo sovraccarico di memoria, supera 8019,

e nessuna colonna può essere rimossa dalla riga.

Considera l'esempio> di una tabella con 600 colonne sparse di tipo bigint.

Se ci sono 571 colonne non nulle, la dimensione totale sul disco è 571 * 12 = 6852 byte. Dopo aver incluso l'overhead di riga aggiuntivo e l'intestazione di colonna sparsa, questo aumenta a circa 6895 byte. La pagina ha ancora circa 1124 byte disponibili sul disco. Ciò può dare l'impressione che ulteriori colonne possano essere aggiornate correttamente. Tuttavia, durante l'aggiornamento, è presente un sovraccarico in memoria pari a 2 * (numero di colonne sparse non nulle). In questo esempio, incluso l'overhead aggiuntivo - 2 * 571 = 1142 byte - aumenta la dimensione della riga sul disco a circa 8037 byte. Questa dimensione supera la dimensione massima consentita di 8019 byte. Poiché tutte le colonne sono tipi di dati a lunghezza fissa, non possono essere rimosse dalla riga. Di conseguenza, l'aggiornamento non riesce con l'errore 576.

maggiori dettagli sul link sopra, tuttavia preferisco pubblicare qui questo avviso anche:

La modifica di una colonna da sparsa a non sparsa o da non sparsa a sparsa richiede la modifica del formato di archiviazione della colonna.

Il motore di database di SQL Server utilizza la seguente procedura per eseguire questa modifica:

1 - Aggiunge una nuova colonna alla tabella nella nuova dimensione e formato di archiviazione.

2 - Per ogni riga della tabella, aggiorna e copia il valore archiviato nella vecchia colonna nella nuova colonna.

3 - Rimuove la vecchia colonna dallo schema della tabella.

4 - Ricostruisce la tabella (se non è presente alcun indice cluster) o ricostruisce l'indice cluster per recuperare lo spazio utilizzato dalla vecchia colonna.


1
Ciao. Un po 'tardi nella mischia, ma sì, mentre abbiamo abbandonato l'approccio descritto in questo argomento molto tempo fa, recentemente ci siamo tornati su con un approccio più selettivo. Fondamentalmente, abbiamo esaminato l'utilizzo delle statistiche e il modello di business per confermare gli indici su una tabella per tabella. Quindi lo ha testato aggiungendo un nuovo indice filtrato sul lato di quello normale e ho verificato per alcune settimane quale è stato utilizzato. Dopo aver confermato che SOLO gli indici filtrati sono stati utilizzati nei nuovi piani, abbiamo eliminato quelli normali non filtrati.
Kahn,

1
Inoltre, abbiamo modificato alcune colonne in tipi sparsi. Il problema con ciò, tuttavia, è che, come vedrai da MSDN, la modifica di un tipo di colonna in radicale costringe sostanzialmente a ricreare l'intero indice cluster. Rendendolo piuttosto pesante per tavoli grandi e complessi. Quindi abbiamo rinominato i vincoli e la tabella, ne abbiamo creato uno nuovo con lo stesso modello e nome originale ma con colonne sparse e quindi trasferito i dati nella nuova tabella in batch appropriati. Quindi, una volta verificato che tutto fosse a posto e che tutti gli indici e gli FK fossero di nuovo a posto, hanno lasciato cadere i vecchi tavoli.
Kahn,

1
Inoltre, in alcuni casi l'uso della compressione delle pagine era di gran lunga preferibile, quindi abbiamo finito per farlo. È anche utile poiché puoi semplicemente creare l'indice cluster esistente con DROP_EXISTING = ON, per renderlo molto, molto più veloce rispetto alla rotta sparsa. Soprattutto perché evita la seccatura di ri-gestire indici e FK.
Kahn,
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.