Un reindicizzazione aggiorna le statistiche?


43

Ho fatto il corso MS10775A la scorsa settimana e una domanda che è emersa a cui il trainer non è stato in grado di rispondere in modo affidabile è:

Un reindicizzazione aggiorna le statistiche?

Abbiamo trovato discussioni online sostenendo sia che lo fa sia che non lo fa.


È utile notare che a REINDEXaggiorna le statistiche delle colonne come effetto collaterale della ricostruzione dell'indice: non è necessario aggiornare le statistiche. I dati nella tabella non cambiano. Sono gli stessi dati, solo a) spostato la sua posizione sul piatto rotante (quando una pagina viene riorganizzata), oppure b) seduto in una pagina diversa (nel caso di una ricostruzione). Quindi: una ri-index fa update (alcuni) statistiche: non c'è bisogno di farlo.
Ian Boyd,

Risposte:


51

Puoi tenere presente quanto segue quando ti preoccupi dell'aggiornamento delle statistiche (copiato da Ricostruzione degli indici e aggiornamento delle statistiche (Benjamin Nevarez)

  1. Per impostazione predefinita, l' UPDATE STATISTICSistruzione utilizza solo un campione di record della tabella. Utilizzando UPDATE STATISTICS WITH FULLSCANverrà eseguita la scansione dell'intera tabella.

  2. Per impostazione predefinita, l' UPDATE STATISTICSistruzione aggiorna le statistiche dell'indice e della colonna. L'uso COLUMNSdell'opzione aggiornerà solo le statistiche delle colonne. L'uso INDEXdell'opzione aggiornerà solo le statistiche dell'indice.

  3. La ricostruzione di un indice , ad esempio utilizzando ALTER INDEX … REBUILD, aggiornerà anche le statistiche dell'indice con l'equivalente dell'utilizzo a WITH FULLSCAN meno che la tabella non sia partizionata, nel qual caso le statistiche vengono campionate solo (si applica a SQL Server 2012 e versioni successive).

  4. Le statistiche create manualmente utilizzando CREATE STATISTICSnon vengono aggiornate da alcuna ALTER INDEX ... REBUILDoperazione, incluso ALTER TABLE ... REBUILD. ALTER TABLE ... REBUILDaggiorna le statistiche per l'indice cluster, se ne è definito uno nella tabella da ricostruire.

  5. La riorganizzazione di un indice , ad esempio l'utilizzo ALTER INDEX … REORGANIZEnon aggiorna alcuna statistica.

La risposta breve è che è necessario utilizzare UPDATE STATISTICSper aggiornare le statistiche delle colonne e che una ricostruzione dell'indice aggiornerà solo le statistiche dell'indice. È possibile forzare un aggiornamento di tutte le statistiche su una tabella, comprese le statistiche indice e le statistiche create manualmente, con la UPDATE STATISTICS (tablename) WITH FULLSCAN;sintassi.

Il seguente codice illustra le regole incapsulate sopra:

Innanzitutto, creeremo una tabella con un paio di colonne e un indice cluster:

USE tempdb;

IF OBJECT_ID(N'dbo.SomeTable', N'U') IS NOT NULL
DROP TABLE dbo.SomeTable;

CREATE TABLE dbo.SomeTable
(
    rn int NOT NULL IDENTITY(1,1)
        CONSTRAINT pk
        PRIMARY KEY NONCLUSTERED
    , i int NOT NULL INDEX i 
    , d sysname NOT NULL
) ON [PRIMARY] WITH (DATA_COMPRESSION = NONE);

CREATE UNIQUE CLUSTERED INDEX cx ON dbo.SomeTable (i, d);

CREATE STATISTICS d ON dbo.SomeTable (d) WITH FULLSCAN;

INSERT INTO dbo.SomeTable (d, i)
SELECT c1.name, c1.id
FROM sys.syscolumns c1;

Questa query mostra la data dell'ultimo aggiornamento di ogni oggetto stats:

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';

I risultati mostrano che non sono ancora stati effettuati aggiornamenti, il che è corretto da quando abbiamo appena creato la tabella:

╔═══════════════╦═══════════╦═══════════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═══════════╣
║ dbo.SomeTable ║ cx ║ NULL ║
║ dbo.SomeTable ║ i ║ NULL ║
║ dbo.SomeTable ║ pk ║ NULL ║
║ dbo.SomeTable ║ d ║ NULL ║
╚═══════════════╩═══════════╩═══════════╝

Ricostruiamo l'intera tabella e vediamo se aggiorna le statistiche:

ALTER TABLE dbo.SomeTable REBUILD;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═════════════════════ ════╣
║ dbo. Qualche tabella ║ cx ║ 2018-09-17 14: 09: 13.590 ║
║ dbo.SomeTable ║ i ║ NULL ║
║ dbo.SomeTable ║ pk ║ NULL ║
║ dbo.SomeTable ║ d ║ NULL ║
╚═══════════════╩═══════════╩═════════════════════ ════╝

I risultati mostrano che sono state aggiornate solo le statistiche dell'indice cluster .

Successivamente, eseguiamo un'operazione discreta UPDATE STATS:

UPDATE STATISTICS dbo.SomeTable(d) WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';

Come puoi vedere, abbiamo appena aggiornato le statistiche nella dcolonna:

╔═══════════════╦═══════════╦═════════════════════ ════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═════════════════════ ════╣
║ dbo. Qualche tabella ║ cx ║ 2018-09-17 14: 09: 13.590 ║
║ dbo.SomeTable ║ i ║ NULL ║
║ dbo.SomeTable ║ pk ║ NULL ║
║ dbo. Qualche tabella ║ d ║ 2018-09-17 14: 09: 13.597 ║
╚═══════════════╩═══════════╩═════════════════════ ════╝

Ora aggiorneremo le statistiche sull'intera tabella:

UPDATE STATISTICS dbo.SomeTable WITH FULLSCAN;

SELECT ObjectName = sc.name + N'.' + o.name
    , StatsName = s.name
    , StatsDate = STATS_DATE(s.object_id, s.stats_id)
FROM sys.stats s
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE sc.name = N'dbo'
    AND o.name = N'SomeTable';
╔═══════════════╦═══════════╦═════════════════════ ════╗
║ ObjectName ║ StatsName ║ StatsDate ║
╠═══════════════╬═══════════╬═════════════════════ ════╣
║ dbo. Qualche tabella ║ cx ║ 2018-09-17 14: 09: 13.600 ║
║ dbo. Qualche tabella ║ i ║ 2018-09-17 14: 09: 13.600 ║
║ dbo. Qualche tabella ║ pk ║ 2018-09-17 14: 09: 13.603 ║
║ dbo. Qualche tabella ║ d ║ 2018-09-17 14: 09: 13.607 ║
╚═══════════════╩═══════════╩═════════════════════ ════╝

Come puoi vedere, l'unico modo per essere certi che tutte le statistiche siano aggiornate è di aggiornarle manualmente o di aggiornare l'intera tabella UPDATE STATISTICS (table);.


@JeremyWeir - come puoi vedere dal codice di esempio che ho appena aggiunto alla domanda sopra, le uniche statistiche aggiornate sono quelle esplicitamente aggiornate tramite una ALTER INDEX ... REBUILDo una UPDATE STATISTICSdichiarazione. Se la tabella stessa viene ricostruita, vengono aggiornate solo le statistiche dell'indice cluster. Cordiali saluti, una chiave primaria e un indice cluster non sono necessariamente supportati dallo stesso oggetto indice.
Max Vernon,

5

La pagina Microsoft Docs per le statistiche di SQL Server indica :

Operazioni come la ricostruzione, la deframmentazione o la riorganizzazione di un indice non cambiano la distribuzione dei dati. Pertanto, non è necessario aggiornare le statistiche dopo aver eseguito ALTER INDEX REBUILD, DBCC DBREINDEX, DBCC INDEXDEFRAG o ALTER INDEX REORGANIZE . Query Optimizer aggiorna le statistiche quando si ricostruisce un indice su una tabella o si visualizza con ALTER INDEX REBUILD o DBCC DBREINDEX, tuttavia questo aggiornamento delle statistiche è un sottoprodotto della ricostruzione dell'indice. Query Optimizer non aggiorna le statistiche dopo le operazioni DBCC INDEXDEFRAG o ALTER INDEX REORGANIZE.

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.