Qual è l'architettura dell'indice appropriata quando viene forzata l'implementazione di IsDeleted (eliminazioni soft)?


16

Attualmente, abbiamo un database e un'applicazione esistenti che sono completamente funzionali. Non ho la possibilità di cambiare l'architettura a questo punto. Oggi, ogni tabella nel database ha un campo "IsDeleted" NOT NULL BIT con un valore predefinito di '0'. Quando l'applicazione "elimina" i dati, aggiorna semplicemente il flag IsDeleted a 1.

Quello che ho difficoltà a capire è come dovrebbero essere strutturati gli indici su ciascuna delle tabelle. In questo momento, ogni query / join / etc implementa sempre il controllo IsDeleted. È uno standard che i nostri sviluppatori devono seguire. Detto questo, sto cercando di determinare se tutti i miei indici di chiave primaria in cluster su ciascuna delle tabelle devono essere modificati per includere la chiave primaria E il campo BIT IsDeleted. Inoltre, poiché OGNI query / join / ecc. deve implementare il controllo IsDeleted, è un presupposto appropriato che OGNI SINGOLO indice (anche non cluster) dovrebbe includere il campo IsDeleted come primo campo dell'indice?

Un'altra domanda che ho riguarda gli indici filtrati. Comprendo che potrei mettere filtri sugli indici come "WHERE IsDeleted = 0" per ridurre la dimensione degli indici. Tuttavia, poiché ogni join / query dovrà implementare il controllo IsDeleted, ciò impedirebbe l'utilizzo dell'indice filtrato (poiché la colonna IsDeleted viene utilizzata in join / query)?

Ricorda, non ho la possibilità di cambiare l'approccio IsDeleted.

Risposte:


13

L'approccio più semplice qui è quello di lasciare da soli le chiavi e gli indici cluster e utilizzare gli indici filtrati per gli indici non cluster.

Inoltre, è possibile migrare alcune tabelle di grandi dimensioni in heap partizionati o negli archivi di colonne cluster (SQL Server 2016+), lasciando la chiave primaria e gli indici univoci non partizionati. Ciò consentirebbe di inviare le colonne non chiave per le righe IsDeleted a una struttura di dati separata, che potrebbe inoltre essere compressa in modo diverso o archiviata in un filegroup diverso.

E assicurati che gli sviluppatori utilizzino un parametro letterale anziché un parametro per filtrare le righe IsDeleted. Con un parametro, SQL Server deve utilizzare lo stesso piano di query per entrambi i casi.

PER ESEMPIO

SELECT ... WHERE ... AND IsDeleted=0

E non:

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

L'uso di un parametro impedisce l'uso dell'indice filtrato e può causare problemi con lo sniffing dei parametri.


Data l'ubiquità e l'importanza della IsDeletedcolonna, indipendentemente dall'archiviazione fisica, probabilmente avrebbe senso esporre i dati attraverso due viste (opzionalmente in schemi diversi), risolvendo sia il problema della parametrizzazione sia commettendo errori nell'accesso ai dati che non avrebbero dovuto essere accesso meno probabile. L'accesso ai dati di base è rilevante solo per i rari casi in cui i dati cancellati e quelli non cancellati devono essere combinati in qualche modo e quando le righe devono essere commutate su "cancellate".
Jeroen Mostert,

@JeroenMostert un buon consiglio. RLS può essere utilizzato anche qui, o qualcosa come EF Core Global Query Filters. docs.microsoft.com/en-us/ef/core/querying/filters
David Browne - Microsoft

9

Questa potrebbe essere un'opinione impopolare, ma non credo che ci sia un "fallo ovunque" / una taglia adatta a tutte le risposte alla tua domanda.

Se si dispone di query che eseguono la scansione di molte righe IsDeleted senza motivo, una soluzione è quella di creare un indice filtrato e non cluster per soddisfare tale query.

Un'altra opzione è quella di creare una vista indicizzata che potrebbe essere sfruttata da una serie di query diverse, che viene filtrata solo per le righe non eliminate. Ciò potrebbe essere particolarmente utile su Enterprise Edition, in cui la corrispondenza della vista indicizzata automatica funziona senza fornire un NOEXPANDsuggerimento.

Per le tabelle di piccole dimensioni o le tabelle che vengono lette pesantemente, l'aggiunta di indici o viste filtrate non cluster o qualsiasi altra cosa potrebbe semplicemente aggiungere un sovraccarico non necessario al database.


2

Partendo dal presupposto ragionevole che le cancellazioni sono rare, nessuna modifica agli indici è una soluzione appropriata.

Ho scoperto che prima o poi bisogna cercare i riferimenti alle righe cancellate e che le righe negli indici improvvisamente ne valgono la pena.

Si noti che, a meno che non si utilizzino le visualizzazioni, è necessario modificare tutte le query per includere comunque i filtri.


0

Ho visto un sistema in cui il flag IS_DELETED è 0 o il valore del PK. In altri sistemi era il negativo del PK.

Poiché la maggior parte delle query ha recuperato i valori con la chiave "naturale" o aziendale (a volte multi-campo), non ha mai eseguito query da PK se non attraverso i join; ma hanno sempre aggiunto un AND IS_DELETED = 0 alla fine per la tabella principale e per tutte le tabelle unite.

Questo sistema aveva anche una tabella di controllo per ogni tabella transazionale che tracciava le modifiche; e l'applicazione aveva una funzione per visualizzare tutte le modifiche ai dati inclusi i dati eliminati.


0

Spero che tu abbia il diritto e la possibilità di cambiare query.

Tuttavia, poiché ogni join / query dovrà implementare il controllo IsDeleted, ciò impedirebbe l'utilizzo dell'indice filtrato (poiché la colonna IsDeleted viene utilizzata in join / query)?

Volevo dire un punto importante, spero di essere in grado di spiegarlo.

In query complesse dove Transaction tablee le Mastertabelle vengono utilizzate entrambe.

Utilizzare IsDeleted=0solo in Transactiontabella. Non utilizzare in Mastertabella.

Esempio,

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

Non ha senso c.isdeleted=0(usare nella Categorytabella). Non è necessario.

Allo stesso modo ha senso usare P.isdeleted=0?

Perché voglio tutti gli ordini non cancellati e i loro dettagli.

Come può Productessere eliminato quando Orderè Activeo ovunque Productidsia riferimento.

Quindi in questo modo se esegui il debug con attenzione in una query importante, potresti essere in grado di rimuovere alcuni dei isdeleted = 0.

Non creare alla cieca un indice filtrato, seleziona prima tutte quelle query molto importanti e lente.

Ottimizza le query lente quindi decidi solo su Indice filtrato o su Ottimizza indice.

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.