Benjamin Nevarez er en uafhængig konsulent baseret i Los Angeles, Californien, som har specialiseret sig i tuning og optimering af SQL Server-forespørgsler. Han er forfatter til "SQL Server 2014 Query Tuning &Optimization" og "Inside the SQL Server Query Optimizer" og medforfatter til "SQL Server 2012 Internals". Med mere end 20 års erfaring i relationelle databaser har Benjamin også været foredragsholder ved mange SQL Server-konferencer, herunder PASS Summit, SQL Server Connections og SQLBits. Benjamins blog kan findes på http://www.benjaminnevarez.com, og han kan også nås via e-mail på admin på benjaminnevarez dot com og på twitter på @BenjaminNevarez.
Et stort problem ved opdatering af statistik i store tabeller i SQL Server er, at hele tabellen altid skal scannes, for eksempel ved brug af WITH FULLSCAN
mulighed, selvom kun de seneste data er ændret. Dette gælder også, når du bruger partitionering:selvom kun den nyeste partition var ændret siden sidste gang, statistik blev opdateret, krævede opdatering af statistik igen for at scanne hele tabellen inklusive alle de partitioner, der ikke ændrede sig. Inkrementelle statistikker, en ny SQL Server 2014-funktion, kan hjælpe med dette problem.
Ved at bruge trinvis statistik kan du kun opdatere den eller de partitioner, du har brug for, og oplysningerne om disse partitioner vil blive flettet sammen med den eksisterende information for at skabe det endelige statistikobjekt. En anden fordel ved inkrementel statistik er, at den procentdel af dataændringer, der kræves for at udløse en automatisk opdatering af statistik, nu fungerer på partitionsniveauet, hvilket grundlæggende betyder, at der nu kun kræves 20% af de ændrede rækker (ændringer på den førende statistikkolonne) pr. partition. Desværre er histogrammet stadig begrænset til 200 trin for hele statistikobjektet i denne version af SQL Server.
Lad os se på et eksempel på, hvordan du kan opdatere statistik på et partitionsniveau for at udforske dens adfærd i det mindste fra og med SQL Server 2014 CTP2. Først skal vi oprette en partitioneret tabel ved hjælp af AdventureWorks2012-databasen:
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
Bemærk:For detaljer om partitionering og CREATE PARTITION FUNCTION / SCHEME
udsagn henvises til Opdelte tabeller og indekser i Books Online.
Vi har i øjeblikket data til at udfylde 12 partitioner. Lad os starte med først at udfylde 11.
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate < '2008-08-01';
Hvis det er nødvendigt, kan du bruge følgende erklæring til at inspicere indholdet af partitionerne:
SELECT * FROM sys.partitions WHERE object_id = OBJECT_ID('dbo.TransactionHistory');
Lad os oprette et inkrementelt statistikobjekt ved hjælp af CREATE STATISTICS
sætning med den nye INCREMENTAL
klausul sat til ON
(OFF
er standard):
CREATE STATISTICS incrstats ON dbo.TransactionHistory(TransactionDate) WITH FULLSCAN, INCREMENTAL = ON;
Du kan også oprette trinvis statistik, mens du opretter et indeks ved hjælp af den nye STATISTICS_INCREMENTAL
klausul i CREATE INDEX
erklæring.
Du kan inspicere det oprettede statistikobjekt ved hjælp af DBCC
:
DBCC SHOW_STATISTICS('dbo.TransactionHistory', incrstats);
Du vil blandt andet bemærke, at histogrammet har 200 trin (kun de sidste 3 vist her):
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 |
Oprindelige DBCC-resultater
Så vi har allerede det maksimale antal trin i et statistikobjekt. Hvad ville der ske, hvis du tilføjer data til en ny partition? Lad os tilføje data til partition 12:
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate >= '2008-08-01';
Nu opdaterer vi statistikobjektet ved hjælp af følgende sætning:
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH RESAMPLE ON PARTITIONS(12);
Bemærk den nye syntaks, der angiver partitionen, hvor du kan angive flere partitioner, adskilt med komma. UPDATE STATISTICS
sætning læser de angivne partitioner og fusionerer derefter deres resultater med det eksisterende statistikobjekt for at bygge den globale statistik. Bemærk RESAMPLE
klausul; dette er påkrævet, da partitionsstatistikker skal have de samme samplingsfrekvenser for at blive flettet for at bygge den globale statistik. Selvom kun den angivne partition blev scannet, kan du se, at SQL Server har omarrangeret histogrammet. De sidste tre trin viser nu data for den tilføjede partition. Du kan også sammenligne originalen med det nye histogram for andre mindre forskelle:
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-resultater efter den trinvise opdatering
Hvis du af en eller anden grund vil deaktivere den trinvise statistik, kan du bruge følgende erklæring til at gå tilbage til den oprindelige adfærd (eller eventuelt bare slippe statistikobjektet og oprette et nyt).
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH FULLSCAN, INCREMENTAL = OFF;
Efter deaktivering af den trinvise statistik vil forsøg på at opdatere en partition som vist tidligere returnere følgende fejlmeddelelse:
Msg 9111, Level 16, State 1OPDATERING STATISTIK PÅ PARTITIONER syntaks er ikke understøttet for ikke-inkrementel statistik.
Endelig kan du også aktivere inkrementel statistik for din automatiske statistik på databaseniveau, hvis det er nødvendigt. Dette kræver INCREMENTAL = ON
klausul i ALTER DATABASE
sætning og kræver naturligvis også AUTO_CREATE_STATISTICS
indstillet til ON
.