Benjamin Nevarez è un consulente indipendente con sede a Los Angeles, California, specializzato nell'ottimizzazione e nell'ottimizzazione delle query di SQL Server. È autore di "SQL Server 2014 Query Tuning &Optimization" e "Inside the SQL Server Query Optimizer" e coautore di "SQL Server 2012 Internals". Con oltre 20 anni di esperienza nei database relazionali, Benjamin è stato anche relatore in molte conferenze su SQL Server, tra cui il PASS Summit, SQL Server Connections e SQLBits. Il blog di Benjamin può essere trovato su http://www.benjaminnevarez.com e può anche essere raggiunto via e-mail all'indirizzo admin di benjaminnevarez dot com e su Twitter all'indirizzo @BenjaminNevarez.
Un grosso problema con l'aggiornamento delle statistiche in tabelle di grandi dimensioni in SQL Server è che l'intera tabella deve sempre essere scansionata, ad esempio quando si utilizza WITH FULLSCAN
opzione, anche se sono stati modificati solo i dati recenti. Questo vale anche quando si utilizza il partizionamento:anche se solo la partizione più recente è stata modificata dall'ultimo aggiornamento delle statistiche, è necessario aggiornare nuovamente le statistiche per eseguire la scansione dell'intera tabella, comprese tutte le partizioni che non sono state modificate. Le statistiche incrementali, una nuova funzionalità di SQL Server 2014, possono aiutare con questo problema.
Usando le statistiche incrementali puoi aggiornare solo la partizione o le partizioni di cui hai bisogno e le informazioni su queste partizioni verranno unite alle informazioni esistenti per creare l'oggetto statistico finale. Un altro vantaggio delle statistiche incrementali è che la percentuale di modifiche ai dati richiesta per attivare un aggiornamento automatico delle statistiche ora funziona a livello di partizione, il che significa sostanzialmente che ora è richiesto solo il 20% delle righe modificate (modifiche nella colonna principale delle statistiche) per partizione. Sfortunatamente l'istogramma è ancora limitato a 200 passaggi per l'intero oggetto statistiche in questa versione di SQL Server.
Esaminiamo un esempio di come aggiornare le statistiche a livello di partizione per esplorarne il comportamento almeno a partire da SQL Server 2014 CTP2. Per prima cosa dobbiamo creare una tabella partizionata utilizzando il database AdventureWorks2012:
CREATE PARTITION FUNCTION TransactionRangePF1 (DATETIME) AS RANGE RIGHT FOR VALUES ( '20071001', '20071101', '20071201', '20080101', '20080201', '20080301', '20080401', '20080501', '20080601', '20080701', '20080801' ); GO CREATE PARTITION SCHEME TransactionsPS1 AS PARTITION TransactionRangePF1 TO ( [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY] ); GO CREATE TABLE dbo.TransactionHistory ( TransactionID INT NOT NULL, -- not bothering with IDENTITY here ProductID INT NOT NULL, ReferenceOrderID INT NOT NULL, ReferenceOrderLineID INT NOT NULL DEFAULT (0), TransactionDate DATETIME NOT NULL DEFAULT (GETDATE()), TransactionType NCHAR(1) NOT NULL, Quantity INT NOT NULL, ActualCost MONEY NOT NULL, ModifiedDate DATETIME NOT NULL DEFAULT (GETDATE()), CONSTRAINT CK_TransactionType CHECK (UPPER(TransactionType) IN (N'W', N'S', N'P')) ) ON TransactionsPS1 (TransactionDate); GO
Nota:per dettagli sul partizionamento e su CREATE PARTITION FUNCTION / SCHEME
fare riferimento a Tabelle e indici partizionati nella documentazione in linea.
Al momento disponiamo di dati per popolare 12 partizioni. Cominciamo col popolarne prima solo 11.
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate < '2008-08-01';
Se necessario, è possibile utilizzare la seguente istruzione per esaminare il contenuto delle partizioni:
SELECT * FROM sys.partitions WHERE object_id = OBJECT_ID('dbo.TransactionHistory');
Creiamo un oggetto di statistica incrementale usando il CREATE STATISTICS
dichiarazione con il nuovo INCREMENTAL
clausola impostata su ON
(OFF
è l'impostazione predefinita):
CREATE STATISTICS incrstats ON dbo.TransactionHistory(TransactionDate) WITH FULLSCAN, INCREMENTAL = ON;
Puoi anche creare statistiche incrementali mentre crei un indice usando il nuovo STATISTICS_INCREMENTAL
clausola del CREATE INDEX
dichiarazione.
Puoi ispezionare l'oggetto delle statistiche creato usando DBCC
:
DBCC SHOW_STATISTICS('dbo.TransactionHistory', incrstats);
Tra l'altro, noterai che l'istogramma ha 200 passi (solo gli ultimi 3 mostrati qui):
RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | |
198 | 25-07-2008 00:00:00.000 | 187 | 100 | 2 |
199 | 27-07-2008 00:00:00.000 | 103 | 101 | 1 |
200 | 31-07-2008 00:00:00.000 | 281 | 131 | 3 |
Risultati DBCC iniziali
Quindi abbiamo già il massimo di passaggi in un oggetto di statistica. Cosa accadrebbe se aggiungi dati a una nuova partizione? Aggiungiamo i dati alla partizione 12:
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate >= '2008-08-01';
Ora aggiorniamo l'oggetto statistiche usando la seguente istruzione:
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH RESAMPLE ON PARTITIONS(12);
Nota la nuova sintassi che specifica la partizione, dove puoi specificare più partizioni, separate da virgola. Il UPDATE STATISTICS
legge le partizioni specificate e quindi unisce i loro risultati con l'oggetto statistico esistente per creare le statistiche globali. Nota il RESAMPLE
clausola; questo è necessario poiché le statistiche di partizione devono avere le stesse frequenze di campionamento per essere unite per creare le statistiche globali. Sebbene sia stata analizzata solo la partizione specificata, è possibile notare che SQL Server ha riorganizzato l'istogramma. Gli ultimi tre passaggi ora mostrano i dati per la partizione aggiunta. Puoi anche confrontare l'originale con il nuovo istogramma per altre differenze minori:
RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | |
197 | 31-07-2008 00:00:00.000 | 150 | 131 | 2 |
198 | 12-08-2008 00:00:00.000 | 300 | 36 | 9 |
199 | 22-08-2008 00:00:00.000 | 229 | 43 | 7 |
200 | 2008-09-03 00:00:00.000 | 363 | 37 | 11 |
Risultati DBCC dopo l'aggiornamento incrementale
Se per qualsiasi motivo desideri disabilitare le statistiche incrementali, puoi utilizzare la seguente istruzione per tornare al comportamento originale (o facoltativamente semplicemente rilasciare l'oggetto statistiche e crearne uno nuovo).
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH FULLSCAN, INCREMENTAL = OFF;
Dopo aver disabilitato le statistiche incrementali provando ad aggiornare una partizione come mostrato in precedenza verrà restituito il seguente messaggio di errore:
Msg 9111, livello 16, stato 1UPDATE STATISTICS ON PARTITIONS la sintassi non è supportata per le statistiche non incrementali.
Infine, puoi anche abilitare le statistiche incrementali per le tue statistiche automatiche a livello di database, se necessario. Ciò richiede INCREMENTAL = ON
clausola nel ALTER DATABASE
istruzione e ovviamente richiede anche AUTO_CREATE_STATISTICS
impostato su ON
.