Бенджамин Неварез е независим консултант със седалище в Лос Анджелис, Калифорния, който е специализиран в настройката и оптимизацията на заявки на SQL Server. Той е автор на „SQL Server 2014 Query Tuning &Optimization“ и „Inside the SQL Server Query Optimizer“ и съавтор на „SQL Server 2012 Internals“. С повече от 20 години опит в релационни бази данни, Бенджамин е бил и лектор на много конференции на SQL Server, включително PASS Summit, SQL Server Connections и SQLBits. Блогът на Бенджамин може да бъде намерен на адрес http://www.benjaminnevarez.com и той може да бъде достигнат и по имейл на admin на benjaminnevarez dot com и в Twitter на @BenjaminNevarez.
Основен проблем с актуализирането на статистически данни в големи таблици в SQL Server е, че цялата таблица винаги трябва да бъде сканирана, например при използване на WITH FULLSCAN
опция, дори ако са се променили само последните данни. Това е вярно и при използване на разделяне:дори само най-новият дял да се е променил от последния път, когато статистиката е била актуализирана, актуализирането на статистиката отново е необходимо, за да се сканира цялата таблица, включително всички дялове, които не са се променили. Инкременталната статистика, нова функция на SQL Server 2014, може да помогне с този проблем.
Използвайки инкрементални статистически данни, можете да актуализирате само дяла или дяловете, от които се нуждаете, и информацията за тези дялове ще бъде обединена със съществуващата информация, за да създадете окончателния статистически обект. Друго предимство на инкременталната статистика е, че процентът промени в данните, необходими за задействане на автоматична актуализация на статистиката, сега работи на ниво дял, което основно означава, че сега са необходими само 20% от променените редове (промени в водещата статистическа колона) на дял. За съжаление хистограмата все още е ограничена до 200 стъпки за целия статистически обект в тази версия на SQL Server.
Нека разгледаме пример за това как можете да актуализирате статистиката на ниво дял, за да проучите поведението му поне спрямо SQL Server 2014 CTP2. Първо трябва да създадем разделена таблица, използвайки базата данни 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
Забележка:За подробности относно разделянето на дялове и CREATE PARTITION FUNCTION / SCHEME
изявления, моля, вижте Разделени таблици и индекси в Books Online.
В момента имаме данни за попълване на 12 дяла. Нека започнем, като първо попълним само 11.
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate < '2008-08-01';
Ако е необходимо, можете да използвате следния оператор, за да проверите съдържанието на дяловете:
SELECT * FROM sys.partitions WHERE object_id = OBJECT_ID('dbo.TransactionHistory');
Нека създадем инкрементален статистически обект, използвайки CREATE STATISTICS
изявление с новия INCREMENTAL
клауза, зададена на ON
(OFF
е по подразбиране):
CREATE STATISTICS incrstats ON dbo.TransactionHistory(TransactionDate) WITH FULLSCAN, INCREMENTAL = ON;
Можете също така да създавате постепенна статистика, докато създавате индекс, като използвате новия STATISTICS_INCREMENTAL
клауза на CREATE INDEX
изявление.
Можете да проверите създадения статистически обект с помощта на DBCC
:
DBCC SHOW_STATISTICS('dbo.TransactionHistory', incrstats);
Освен всичко друго, ще забележите, че хистограмата има 200 стъпки (само последните 3 са показани тук):
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 | 2008-07-31 00:00:00,000 | 281 | 131 | 3 |
Първоначални резултати от DBCC
Така че вече имаме максималния брой стъпки в статистически обект. Какво ще се случи, ако добавите данни към нов дял? Нека добавим данни към дял 12:
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate >= '2008-08-01';
Сега актуализираме статистическия обект, използвайки следния израз:
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH RESAMPLE ON PARTITIONS(12);
Обърнете внимание на новия синтаксис, определящ дяла, където можете да посочите множество дялове, разделени със запетая. UPDATE STATISTICS
оператор чете посочените дялове и след това обединява техните резултати със съществуващия статистически обект, за да изгради глобалната статистика. Обърнете внимание на RESAMPLE
клауза; това е необходимо, тъй като статистическите данни за дяловете трябва да имат еднакви честоти на извадка, за да бъдат обединени, за да се изгради глобалната статистика. Въпреки че е сканиран само посоченият дял, можете да видите, че SQL Server е пренаредил хистограмата. Последните три стъпки вече показват данни за добавения дял. Можете също да сравните оригинала с новата хистограма за други незначителни разлики:
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 | 22.08.2008 00:00:00.000 | 229 | 43 | 7 |
200 | 2008-09-03 00:00:00,000 | 363 | 37 | 11 |
Резултати от DBCC след постепенната актуализация
Ако по някаква причина искате да деактивирате инкременталните статистически данни, можете да използвате следния израз, за да се върнете към първоначалното поведение (или по желание просто пуснете статистическия обект и създадете нов).
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH FULLSCAN, INCREMENTAL = OFF;
След деактивиране на инкременталната статистика, опитът за актуализиране на дял, както е показано по-горе, ще върне следното съобщение за грешка:
Съобщение 9111, ниво 16, състояние 1Актуализиране на СТАТИСТИКАТА НА ДЯЛОВЕТЕ Синтаксисът не се поддържа за ненарастващи статистики.
И накрая, можете също да активирате инкрементални статистически данни за вашите автоматични статистически данни на ниво база данни, ако е необходимо. Това изисква INCREMENTAL = ON
клауза в ALTER DATABASE
изявление и очевидно също изисква AUTO_CREATE_STATISTICS
зададен на ON
.