Risposta semplice:NO. Non puoi aiutare le query ad hoc su una tabella di 238 colonne con un fattore di riempimento del 50% sull'indice cluster.
Risposta dettagliata:
Come ho affermato in altre risposte su questo argomento, il design dell'indice è sia arte che scienza e ci sono così tanti fattori da considerare che ci sono poche, se non nessuna, regole rigide e veloci. È necessario considerare:il volume delle operazioni DML rispetto a SELECT, il sottosistema del disco, altri indici/trigger sulla tabella, la distribuzione dei dati all'interno della tabella, sono query che utilizzano condizioni SARGable WHERE e molte altre cose che non riesco nemmeno a ricordare bene ora.
Posso dire che nessun aiuto può essere fornito per domande su questo argomento senza una comprensione della tabella stessa, dei suoi indici, trigger, ecc. Ora che hai pubblicato la definizione della tabella (ancora in attesa sugli indici ma la definizione della tabella da sola punta a 99% del problema) posso offrire alcuni suggerimenti.
Innanzitutto, se la definizione della tabella è accurata (238 colonne, 50% di fattore di riempimento), puoi praticamente ignorare il resto delle risposte / consigli qui;-). Mi dispiace essere poco politico qui, ma sul serio, è una caccia all'oca senza conoscere i dettagli. E ora che vediamo la definizione della tabella, diventa un po' più chiaro il motivo per cui una semplice query richiederebbe così tanto tempo, anche quando le query di test (Aggiornamento n. 1) sono state eseguite così rapidamente.
Il problema principale qui (e in molte situazioni di scarse prestazioni) è la cattiva modellazione dei dati. 238 colonne non sono proibite così come non è proibito avere 999 indici, ma generalmente non è molto saggio.
Raccomandazioni:
- In primo luogo, questo tavolo ha davvero bisogno di essere rimodellato. Se questa è una tabella di data warehouse, allora forse, ma in caso contrario questi campi devono davvero essere suddivisi in più tabelle che possono avere tutte la stessa PK. Avresti una tabella dei record principali e le tabelle figlie sono solo informazioni dipendenti basate su attributi comunemente associati e il PK di quelle tabelle è lo stesso del PK della tabella principale e quindi anche FK della tabella principale. Ci sarà una relazione 1 a 1 tra le tabelle principali e tutte secondarie.
- L'uso di
ANSI_PADDING OFF
è inquietante, per non dire incoerente all'interno della tabella a causa delle varie aggiunte di colonne nel tempo. Non sono sicuro di poterlo risolvere ora, ma idealmente avresti sempreANSI_PADDING ON
o almeno avere la stessa impostazione su tutti gliALTER TABLE
dichiarazioni. - Considera la creazione di 2 gruppi di file aggiuntivi:tabelle e indici. È meglio non mettere le tue cose in
PRIMARY
poiché è lì che SQL SERVER archivia tutti i suoi dati e metadati sui tuoi oggetti. Crei la tua tabella e l'indice cluster (poiché sono i dati per la tabella) su[Tables]
e tutti gli indici non cluster su[Indexes]
- Aumenta il fattore di riempimento dal 50%. Questo numero basso è probabilmente il motivo per cui lo spazio dell'indice è maggiore dello spazio dati. Eseguire una ricostruzione dell'indice ricreerà le pagine di dati con un massimo di 4k (su una dimensione totale della pagina di 8k) utilizzate per i tuoi dati in modo che la tua tabella sia distribuita su un'ampia area.
- Se la maggior parte o tutte le query hanno "ER101_ORG_CODE" nel
WHERE
condizione, quindi considera di spostarla nella colonna iniziale dell'indice cluster. Supponendo che venga utilizzato più spesso di "ER101_ORD_NBR". Se "ER101_ORD_NBR" viene utilizzato più spesso, mantienilo. Sembra solo, supponendo che i nomi dei campi significhino "OrganizationCode" e "OrderNumber", che "OrgCode" sia un raggruppamento migliore che potrebbe avere più "OrderNumbers" al suo interno. - Punto minore, ma se "ER101_ORG_CODE" è sempre di 2 caratteri, usa
CHAR(2)
invece diVARCHAR(2)
poiché salverà un byte nell'intestazione della riga che tiene traccia delle dimensioni della larghezza variabile e si somma su milioni di righe. - Come altri hanno già detto, usando
SELECT *
danneggerà le prestazioni. Non solo perché richiede a SQL Server di restituire tutte le colonne e quindi è più probabile che esegua una scansione dell'indice in cluster indipendentemente dagli altri indici, ma richiede anche del tempo a SQL Server per passare alla definizione della tabella e tradurre*
in tutti i nomi delle colonne. Dovrebbe essere leggermente più veloce per specificare tutti i 238 nomi di colonna inSELECT
elenco anche se ciò non aiuterà il problema di scansione. Ma hai mai davvero bisogno di tutte e 238 le colonne contemporaneamente?
Buona fortuna!
AGGIORNAMENTO
Per completezza della domanda "come migliorare le prestazioni su una tabella di grandi dimensioni per query ad hoc", va notato che sebbene non sia di aiuto per questo caso specifico, SE qualcuno sta utilizzando SQL Server 2012 (o più recente quando arriva quel momento) e SE la tabella non viene aggiornata, l'utilizzo di Columnstore Indexes è un'opzione. Per maggiori dettagli su questa nuova funzionalità, guarda qui:http://msdn.microsoft.com/en-us/library/gg492088.aspx (credo che siano stati fatti per essere aggiornabili a partire da SQL Server 2014).
AGGIORNAMENTO 2
Ulteriori considerazioni sono:
- Abilita la compressione sull'indice cluster. Questa opzione è diventata disponibile in SQL Server 2008, ma come funzionalità solo per Enterprise Edition. Tuttavia, a partire da SQL Server 2016 SP1 , La compressione dei dati è stata resa disponibile in tutte le edizioni! Consulta la pagina MSDN per la compressione dei dati per i dettagli sulla compressione di righe e pagine.
- Se non puoi utilizzare la compressione dei dati o se non fornisce molti vantaggi per una tabella particolare, SE hai una colonna di tipo a lunghezza fissa (
INT
,BIGINT
,TINYINT
,SMALLINT
,CHAR
,NCHAR
,BINARY
,DATETIME
,SMALLDATETIME
,MONEY
, ecc) e ben oltre il 50% delle righe sonoNULL
, quindi considera l'abilitazione diSPARSE
opzione che è diventata disponibile in SQL Server 2008. Per i dettagli, vedere la pagina MSDN per Usa colonne sparse.