Benjamin Nevarez är en oberoende konsult baserad i Los Angeles, Kalifornien, som specialiserat sig på justering och optimering av SQL Server-frågor. Han är författare till "SQL Server 2014 Query Tuning &Optimization" och "Inside the SQL Server Query Optimizer" och medförfattare till "SQL Server 2012 Internals". Med mer än 20 års erfarenhet av relationsdatabaser har Benjamin även varit föredragshållare vid många SQL Server-konferenser, inklusive PASS Summit, SQL Server Connections och SQLBits. Benjamins blogg finns på http://www.benjaminnevarez.com och han kan också nås via e-post på admin på benjaminnevarez dot com och på twitter på @BenjaminNevarez.
Ett stort problem med att uppdatera statistik i stora tabeller i SQL Server är att hela tabellen alltid måste skannas, till exempel när du använder WITH FULLSCAN
alternativet, även om bara de senaste uppgifterna har ändrats. Detta gäller också när du använder partitionering:även om bara den senaste partitionen hade ändrats sedan senaste gången statistiken uppdaterades, krävdes uppdatering av statistik igen för att skanna hela tabellen inklusive alla partitioner som inte ändrades. Inkrementell statistik, en ny SQL Server 2014-funktion, kan hjälpa till med detta problem.
Med hjälp av inkrementell statistik kan du bara uppdatera den eller de partitioner som du behöver och informationen om dessa partitioner kommer att slås samman med den befintliga informationen för att skapa det slutliga statistikobjektet. En annan fördel med inkrementell statistik är att procentandelen dataändringar som krävs för att utlösa en automatisk uppdatering av statistik nu fungerar på partitionsnivå vilket i princip innebär att nu endast 20% av raderna ändrade (ändringar i den ledande statistikkolumnen) per partition krävs. Tyvärr är histogrammet fortfarande begränsat till 200 steg för hela statistikobjektet i denna version av SQL Server.
Låt oss titta på ett exempel på hur du kan uppdatera statistik på partitionsnivå för att utforska dess beteende åtminstone från och med SQL Server 2014 CTP2. Först måste vi skapa en partitionerad tabell med hjälp av databasen 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
Obs:För detaljer om partitionering och CREATE PARTITION FUNCTION / SCHEME
uttalanden hänvisas till Partitionerade tabeller och index i Books Online.
Vi har för närvarande data för att fylla 12 partitioner. Låt oss börja med att först fylla i endast 11.
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate < '2008-08-01';
Om det behövs kan du använda följande uttalande för att inspektera innehållet i partitionerna:
SELECT * FROM sys.partitions WHERE object_id = OBJECT_ID('dbo.TransactionHistory');
Låt oss skapa ett inkrementellt statistikobjekt med CREATE STATISTICS
uttalande med den nya INCREMENTAL
sats inställd på ON
(OFF
är standard):
CREATE STATISTICS incrstats ON dbo.TransactionHistory(TransactionDate) WITH FULLSCAN, INCREMENTAL = ON;
Du kan också skapa inkrementell statistik samtidigt som du skapar ett index med den nya STATISTICS_INCREMENTAL
satsen i CREATE INDEX
uttalande.
Du kan inspektera det skapade statistikobjektet med DBCC
:
DBCC SHOW_STATISTICS('dbo.TransactionHistory', incrstats);
Bland annat kommer du att märka att histogrammet har 200 steg (endast de 3 sista som visas här):
RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | |
198 | 2008-07-25 00:00:00.000 | 187 | 100 | 2 |
199 | 2008-07-27 00:00:00.000 | 103 | 101 | 1 |
200 | 2008-07-31 00:00:00.000 | 281 | 131 | 3 |
Initiala DBCC-resultat
Så vi har redan det maximala antalet steg i ett statistikobjekt. Vad skulle hända om du lägger till data till en ny partition? Låt oss lägga till data till partition 12:
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate >= '2008-08-01';
Nu uppdaterar vi statistikobjektet med följande uttalande:
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH RESAMPLE ON PARTITIONS(12);
Notera den nya syntaxen som anger partitionen, där du kan ange flera partitioner, separerade med kommatecken. UPDATE STATISTICS
uttalandet läser de angivna partitionerna och slår sedan samman deras resultat med det befintliga statistikobjektet för att bygga den globala statistiken. Notera RESAMPLE
klausul; detta krävs eftersom partitionsstatistiken måste ha samma samplingsfrekvenser för att kunna slås samman för att skapa den globala statistiken. Även om endast den angivna partitionen skannades, kan du se att SQL Server har ordnat om histogrammet. De tre sista stegen visar nu data för den tillagda partitionen. Du kan också jämföra originalet med det nya histogrammet för andra mindre skillnader:
RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | |
197 | 2008-07-31 00:00:00.000 | 150 | 131 | 2 |
198 | 2008-08-12 00:00:00.000 | 300 | 36 | 9 |
199 | 2008-08-22 00:00:00.000 | 229 | 43 | 7 |
200 | 2008-09-03 00:00:00.000 | 363 | 37 | 11 |
DBCC-resultat efter den inkrementella uppdateringen
Om du av någon anledning vill inaktivera den inkrementella statistiken kan du använda följande uttalande för att gå tillbaka till det ursprungliga beteendet (eller eventuellt bara släppa statistikobjektet och skapa ett nytt).
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH FULLSCAN, INCREMENTAL = OFF;
Efter att ha inaktiverat den inkrementella statistiken kommer ett försök att uppdatera en partition som tidigare visat att returnera följande felmeddelande:
Msg 9111, Level 16, State 1UPPDATERA STATISTIK PÅ PARTITIONER syntax stöds inte för icke-inkrementell statistik.
Slutligen kan du även aktivera inkrementell statistik för din automatiska statistik på databasnivå, om det behövs. Detta kräver INCREMENTAL = ON
sats i ALTER DATABASE
och kräver uppenbarligen också AUTO_CREATE_STATISTICS
inställd på ON
.