Devo disabilitare le "statistiche di aggiornamento automatico" in uno scenario di data warehousing?


12

Ho 200 GB di data warehouse in SQL Server.

Ho riscontrato tempi di esecuzione molto lenti per alcune query; ad esempio 12 ore per una deletequery semplice con un inner join.

Dopo aver fatto qualche ricerca con i piani di esecuzione, ho aggiornato le statistiche delle 2 tabelle coinvolte nella query, usando l' WITH FULLSCANopzione.

La query ora viene eseguita in meno di un secondo, quindi sembra che le statistiche non siano aggiornate.

Sto valutando la disabilitazione auto update statisticssul database e l'esecuzione UPDATE STATISTICSmanuale dopo il caricamento del data warehouse. Il data warehouse viene caricato in modo incrementale da un sistema ERP di origine ogni giorno, di notte.

Sono corretto nel presupporre che auto update statisticsin scenari di data warehousing non sia davvero utile? Invece, ha più senso aggiornare manualmente le statistiche dopo che i dati sono stati caricati?


Questa è un'ottima lettura delle statistiche: simple-talk.com/sql/performance/… eseguiamo anche un lavoro quotidiano usando la soluzione di Ola ola.hallengren.com/… per aggiornare le statistiche su 1 TB db. Non disabiliterei l'opzione delle statistiche di aggiornamento automatico.
Joy Walker,

1
Dipende molto da quanti record ci sono nelle tue tabelle e da quanto aggiungi in un batch. In una tabella di righe 1b in cui aggiungi 20 milioni di righe a notte, le tue statistiche verranno aggiornate ogni 10 giorni, il che non è eccezionale.
JNK,

2
Cordiali saluti - esiste un flag di traccia (2371) per modificare la soglia per l'aggiornamento delle statistiche dal 20% fisso a un tasso percentuale dinamico. Vedi di più qui: blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/…
DaniSQL

Link molto istruttivi, grazie! @JNK: Sì, è un DB di grandi dimensioni. La tabella di gestione temporanea ha più di 300m di righe e a seconda del giorno in cui inseriamo qualcosa tra 1m e 10m al giorno. Guarderemo più da vicino le statistiche, come è stato proposto dalla risposta di seguito.
saso,

Risposte:


11

Ecco un white paper su quando si verifica l'auto_aggiornamento delle statistiche . Ecco i punti salienti rispetto agli aggiornamenti automatici delle statistiche:

  • Le dimensioni della tabella sono passate da 0 a> 0 righe (test 1).
  • Il numero di righe nella tabella al momento della raccolta delle statistiche era 500 o inferiore e da allora il colmodctr della colonna principale dell'oggetto statistico è cambiato di oltre 500 (test 2).
  • La tabella aveva più di 500 righe al momento della raccolta delle statistiche e il colmodctr della colonna principale dell'oggetto statistico è cambiato di oltre il 500 + 20% del numero di righe nella tabella al momento della raccolta delle statistiche (test 3) .

Quindi @JNK ha sottolineato in un commento che se hai 1 miliardo di righe in una tabella, per attivare un aggiornamento dovresti avere 20.000.5000 scritture nella prima colonna della statistica.

Prendiamo la seguente struttura:

CREATE TABLE dbo.test_table (
    test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
    test_table_value VARCHAR(50), 
    test_table_value2 BIGINT, 
    test_table_value3 NUMERIC(10,2)
);

CREATE CLUSTERED INDEX cix_test_table ON dbo.test_table (test_table_id, test_table_value);

Ora possiamo controllare per vedere cosa è successo nelle statistiche della terra.

select * 
    from sys.stats
        where object_id = OBJECT_ID('dbo.test_table')

stat_container

Tuttavia, per vedere se si tratta di un oggetto statistico significativo dobbiamo:

dbcc show_statistics('dbo.test_table',cix_test_table)

istogramma

Quindi questa statistica non è stata aggiornata. Questo perché sembra che la statistica non venga aggiornata fino a quando non si SELECTverifica e anche in questo caso SELECTdeve cadere al di fuori di ciò che SQL Server ha nel suo istogramma. Ecco uno script di test che ho eseguito per testare questo:

    CREATE TABLE test_table (
        test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
        test_table_value VARCHAR(50), 
        test_table_value2 BIGINT, 
        test_table_value3 NUMERIC(10,2)
    );

    CREATE CLUSTERED INDEX cix_test_table ON test_table (test_table_id, test_table_value);

    ALTER TABLE test_table ADD CONSTRAINT pk_test_table PRIMARY KEY  (test_table_id)

    SELECT * 
        FROM sys.stats
            WHERE object_id = OBJECT_ID('dbo.test_table')

    --DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table)
    DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

declare @test int = 0

WHILE @test < 1
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT 'one row|select < 1', * FROM test_table WHERE test_table_id < 1;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

SET @test = 1

WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '100 rows(add 99)|select < 100',* FROM test_table WHERE test_table_id < 100;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--get the table up to 500 rows/changes
WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END
SELECT '500 rows(add 400)|select < 100',* FROM test_table WHERE test_table_id < 100;
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
SELECT '500 rows(add 400)|select < 500',* FROM test_table WHERE test_table_id < 500;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--bump it to 501
SET @test = 500;
WHILE @test < 501
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END


SELECT '501 rows(add 1)|select < 501',* FROM test_table WHERE test_table_id < 501;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 600
SET @test = 501;
WHILE @test < 600
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '600 rows (add 100)|select < 600',* FROM test_table WHERE test_table_id < 600;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 700
SET @test = 600;
WHILE @test < 700
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '700 rows (add 100)|select < 700', * FROM test_table WHERE test_table_id < 700;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 1200
SET @test = 700;
WHILE @test < 1200
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '1200 rows (add 500)|select < 1200',* FROM test_table WHERE test_table_id < 1200;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--DROP TABLE test_table

Invece di disabilitare ciecamente le statistiche di auto_update, proverei a esaminare il tuo set di dati per inclinarlo. Se i tuoi dati mostrano un'inclinazione significativa, devi considerare la creazione di statistiche filtrate e quindi decidere se la gestione manuale degli aggiornamenti delle statistiche è la linea di condotta corretta.

Per analizzare l'inclinazione è necessario eseguire DBCC SHOW_STATISTICS(<stat_object>, <index_name>);(nello script sopra senza WITH STAT_HEADER) la particolare combinazione stat / indice che si desidera esaminare. Un modo rapido per controllare il tuo disallineamento sarebbe guardare l'istogramma (terzo set di risultati) e verificare la varianza nel tuo EQ_ROWS. Se è abbastanza coerente, l'inclinazione è minima. Per aumentarlo, guardi la RANGE_ROWScolonna e guardi la varianza lì poiché questo misura quante righe esistono tra ogni passaggio. Infine, puoi prendere il [All density]risultato dal DENSITY_VECTOR(secondo set di risultati) e moltiplicarlo per il [Rows Sampled]valore nel STAT_HEADER(primo set di risultati) e vedere quale sarebbe l'attesa media per una query su quella colonna. Confronti quella media con la tuaEQ_ROWS e se ci sono molti posti in cui varia in modo significativo, allora hai l'inclinazione.

Se scopri di avere un'inclinazione, devi considerare la creazione di alcune statistiche filtrate sugli intervalli che hanno valori molto alti in RANGE_ROWSmodo da poter fornire ulteriori passaggi per una migliore stima di tali valori.

Dopo aver installato queste statistiche filtrate, puoi esaminare la possibilità di aggiornare manualmente le statistiche.


Grazie per la risposta esaustiva. Non ho molta esperienza con le statistiche e questo sembra essere più complicato come pensavo. Daremo un'occhiata più da vicino e seguirai le tue linee guida.
saso,
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.