Perché il mio database è ancora frammentato dopo che ho ricostruito e reindicizzato tutto?


41

Ho un database che ho provato a deframmentare tutte le tabelle contemporaneamente eseguendo questo T-SQL:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

E quindi copiare e incollare l'output in una nuova finestra di query ed eseguirlo. Non ho riscontrato errori, ma ho ancora frammentazione. Ho provato a eseguire entrambi i comandi separatamente e ho ancora frammentazione. Nota: mi è stato reso conto che REORGANIZEnon è necessario da Aaron e sono consapevole che potrei usare sql dinamico per automatizzare questo.

Ho eseguito questo per determinare che ho ancora la frammentazione:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

E ho ottenuto:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

So che mi manca qualcosa di veramente semplice, ma non so cosa.


Quali errori hai riscontrato? C'è anche un motivo per cui lo riorganizzi e ricostruisci la stessa cosa?
Shawn Melton,

Shawn, mi scuso per la mancanza di una parola. Ho avuto nessun errore. Per quanto riguarda il motivo per cui ho eseguito entrambi i comandi, l'ho fatto dopo aver provato ogni comando singolarmente. Ho aggiornato le mie domande.
Justin Dearing il

Risposte:


38

I tavoli sono piccoli. I conteggi delle pagine nelle tue tabelle sono:

11, 8, 6, 5, 13, 8, 10

Occupano 480kb in totale. Non c'è letteralmente nulla da deframmentare.

Modifica: questo merita una spiegazione in più.

A una nuova tabella o indice vengono generalmente assegnate le prime 8 pagine da una dimensione mista, piuttosto che uniforme. Pertanto, è possibile assegnare ciascuna delle prime 8 pagine da diverse estensioni miste. Una tabella o un indice che consuma 8 pagine potrebbe quindi avere 8 frammenti, 1 su ciascuna delle 8 diverse estensioni miste.

Gli script di deframmentazione più utilizzati (un paio di esempi collegati di seguito) tendono ad escludere piccole tabelle per questo motivo. IIRC, <500 pagine sono in una o entrambe. A queste dimensioni, la deframmentazione presenta pochi benefici e le cifre della frammentazione sono potenzialmente distorte dalle allocazioni di entità mista.


Ok, è soddisfacente a meno che qualcun altro non abbia una risposta migliore, segnerò la tua come corretta.
Justin Dearing,

3
+1 Concordato con Mark. Preoccupati per la frammentazione quando in realtà hai alcuni dati. :-)
Aaron Bertrand

Capisco perfettamente quello che stai dicendo. Ma solo per pura curiosità, è perché il motore db non riesce a deframmentare così poche pagine? Voglio dire, ci deve essere una ragione per questo.
Thomas Stringer

3
Non è che non può, ma perché dovrebbe preoccuparsi? In questo modo si avrà un impatto minimo o nullo sull'I / O, soprattutto perché le tabelle così piccole sono quasi sicuramente in memoria.
Aaron Bertrand

1
Appena. Sembra strano, tutto qui. Supponiamo che stia scrivendo un'applicazione per verificare e riferire sulla frammentazione dell'indice, dovrei aggiungere una logica adizionale per testare non solo la percentuale di frammento, ma anche la quantità di pagine in modo che non ci siano falsi allarmi.
Thomas Stringer,

19

Citazione da " Best practice per la deframmentazione dell'indice di Microsoft SQL Server 2000 ":

"La frammentazione influisce sull'I / O del disco. Pertanto, concentrati sugli indici più grandi perché le loro pagine hanno meno probabilità di essere memorizzate nella cache da SQL Server. Usa il conteggio delle pagine riportato da DBCC SHOWCONTIG per avere un'idea delle dimensioni degli indici (ogni pagina è 8 KB di dimensione.) In generale, non dovresti preoccuparti dei livelli di frammentazione degli indici con meno di 1.000 pagine. Nei test, gli indici che contengono più di 10.000 pagine hanno realizzato miglioramenti delle prestazioni, con i maggiori guadagni sugli indici con significativamente più pagine (maggiore di 50.000 pagine) . "

Quindi questo tipo di risposte alla tua domanda e supporta le risposte di Mark e Aaron.

Puoi trovare buone informazioni sulla frammentazione dell'indice nei seguenti articoli di Brent Ozar:

Inoltre ... un blog di grandi informazioni sugli indici in generale (anche sui problemi di frammentazione) è disponibile sul blog di Kimberly Tripp .


12

Questo non ha lo scopo di rispondere alla tua domanda, ma non entrerà mai in un commento. Puoi creare questo script in modo dinamico senza dover copiare e incollare l'output in un'altra finestra. Tenendo conto del fatto che non vi è assolutamente alcun motivo per REORGANIZEe quindi REBUILD:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;

Aaron, grazie per aver sottolineato il sql dinamico, sono ben consapevole del sql dinamico, non avrei automatizzato la soluzione fino a quando non ha funzionato. Gli altri che leggono questo dovrebbero probabilmente essere consapevoli però.
Justin Dearing,
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.