Come ridurre la frammentazione HEAP in SQL Server?


10

di recente ho scoperto che una tabella heap aveva una frammentazione superiore al 70%. Quindi ho deciso di fare un

ALTER TABLE dbo.myTable REBUILD

Abbastanza divertente, dopo ho avuto una frammentazione del 20%. Da allora non c'è più stato scritto su quel tavolo. Così ho deciso di fare la ricostruzione ancora una volta.

Dopo la seconda volta il tavolo ha una frammentazione del 50%, quindi ancora di più! Davvero non capisco come questo possa accadere ...


Cosa intendi quando dici frammentazione logica. È la frammentazione in termini di utilizzo delle pagine di dati. So che non c'è ordine ma i dati non ordinati non sono frammentati di per sé. La frammentazione in questo caso significa un uso efficiente delle pagine di dati.
tuxmania,

2
Immagino che dovremmo chiedere, quanto è grande il tavolo? In righe e pagine.
Cody Konior,

Risposte:


17

Cosa significa frammentazione in un mucchio

Il valore di frammentazione in Heap che si ottiene dalla colonna avg_fragmentation_in_percentinterrogando sys.dm_db_index_physical_statsDMV lo afferma

Frammentazione logica per gli indici o frammentazione dell'estensione per heap nell'unità di allocazione IN_ROW_DATA.

Inoltre lo stesso BOL lo dice

Questa è la percentuale di estensioni non ordinate nelle pagine foglia di un heap. Un'estensione fuori servizio è una per la quale l'estensione che contiene la pagina corrente per un heap non è fisicamente quella successiva dopo l'estensione che contiene la pagina precedente.

Quindi puoi vedere che non è lo spazio libero presente nelle pagine allocate a Heap ma la sequenza variabile di pagine che crea la frammentazione.

Questo può essere dimostrato da un piccolo test. Creiamo una tabella heap e inseriamo alcuni record in essa e quindi controlliamo la frammentazione.

create table dbo.HeapTest
(
Id INT not NULL Default (1),
Col1   char(5000) Not null Default ('Heaps Are Cool')
)

SET NOCOUNT ON

Insert into dbo.Heaptest default values
go 50

select index_type_desc,avg_fragmentation_in_percent,fragment_count,
avg_page_space_used_in_percent,record_count
from sys.dm_db_index_physical_stats(db_id(),object_id('dbo.HeapTest','U'),0,default,'detailed')

Quindi la tabella Heap viene creata con 50 record al suo interno. Di seguito è riportata la frammentazione dopo la query DMV sys.dm_db_index_physical stats

inserisci qui la descrizione dell'immagine

Puoi vedere il avg_fragmentation_in_percentvalore della colonna è del 33%. Ora vediamo come sono organizzate le pagine. Questo può essere fatto utilizzando una query non documentata%%lockres%% . La query sarebbe

SELECT  %%lockres%%, * FROM dbo.HeapTest;

E sotto è come appare l'output. Allegare solo una parte rilevante di esso. La query ha prodotto 50 righe da quando abbiamo inserito 50 righe nella nostra tabella dbo.HeapTest.

inserisci qui la descrizione dell'immagine

Ciò che dice è che la prima pagina ha un ID, 197la pagina successiva ha un ID, 242le pagine successive hanno un ID continuo fino a quando non raggiungiamo l'ID della pagina 264perché dopo otteniamo l'ID della pagina 280. Quindi questo salto nei numeri di ID pagina è ciò che effettivamente causa la frammentazione.

Ora per ricostruire l'heap ed eseguire nuovamente il comando per vedere la frammentazione e come sono organizzate le pagine. Otteniamo la frammentazione come

inserisci qui la descrizione dell'immagine

Ora puoi vedere la frammentazione 14%.

Vediamo i numeri di pagina assegnati

inserisci qui la descrizione dell'immagine

Abbiamo solo un resto di riposo a tutte le pagine vengono assegnate in serie l'ID pagina. Da un solo salto la frammentazione è diminuita considerevolmente.

Ho ricostruito di nuovo l'Heap e ora quando ho controllato la frammentazione era completamente sparito. E l'allocazione dell'ID pagina è simile

inserisci qui la descrizione dell'immagine

Perché la frammentazione è aumentata

Ora per quanto riguarda ciò che potrebbe aver causato l'aumento della frammentazione, possiamo confermarlo al fatto che quando le pagine venivano allocate all'heap non sarebbero state continue, come hai visto sopra ciò che ha causato l'aumento del valore di frammentazione è stato il salto nell'ID PAGINA assegnato alle pagine.

Nella parte posteriore della testa dovresti anche tenere presente che la frammentazione della parola per HEAP non ha alcun significato, come definiresti la frammentazione per un gruppo di pagine non ordinate.

Preoccupato per la frammentazione

Se dovessi davvero affrontare uno scenario in cui la tabella heap è frammentata e rallentare le query, sarebbe meglio creare un indice cluster sulla tabella piuttosto che ricostruirlo. Il motivo è che quando si ricostruiscono heap vengono ricostruiti anche tutti gli indici non cluster sottostanti, facendo sì che il processo di ricostruzione impieghi molto più tempo, utilizzando molte risorse e un registro delle transazioni gonfio. Su un sistema di produzione si cercherebbe sempre di evitarlo. Paolo ha trattato questo argomento nella sua sezione miti sull'heap .

PS: Non utilizzare comandi non documentati sul sistema di produzione. Questo era solo per dimostrazione.


Grazie per la tua analisi dettagliata. Sto affrontando grandi tabelle heap perché alcuni appassionati di data vault pensano che sia molto meglio dell'uso degli indici cluster, ma poi usano molti vincoli di controllo e indici non cluster su questi heap, quindi non vedo davvero il beneficio degli heap in questa situazione. Tuttavia, poiché sono solo lo stupido sviluppatore, devo occuparmene. Grazie ancora per l'intuizione :)
tuxmania,

Come si esegue select index_type_desc, avg_fragmentation_in_percent, fragment_count, avg_page_space_used_in_percent, record_count da sys.dm_db_index_physical_stats (db_id (), object_id ('dbo.HeapTest', 'U' '),' ')' ',' ' un tavolo ? ritorna su tutti gli indici su tutte le tabelle per me anche se ho correttamente specificato il nome della mia tabella in 'object_id'
Mickael

@Mickael Ho usato la funzione db_id () che prenderebbe il database corrente e ho specificatamente dato il nome dell'oggetto in modo che questo guarderà sempre nel database corrente e cerchi Heapteste dia il risultato. Sono sicuro che potresti aver perso qualcosa. Assicurati solo che il livello di compatibilità non sia 80 in quel caso la funzione
db_id

@Grazie, perché non mi consiglia di utilizzare la query non documentata %% lockres %% nella produzione? Potresti spiegarlo in dettaglio?
Ralph,

@ user1624552 Semplicemente perché non è documentato, significa che anche MS non mantiene aggiornata la documentazione a riguardo. Quali sono i suoi effetti collaterali come funziona non è documentato da nessuna parte ed è per questo che gli viene chiesto. Ex c'è il comando fn_dump_dblog () che crea uno scheduler nascosto e che non va bene. Anche questo comando non è supportato. Puoi usarlo ma il rischio risiede su di te.
Shanky,
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.