Чи можливо змусити оптимізатор усунути невідповідні таблиці в цьому розділеному представленні?


22

Я тестую різні архітектури для великих таблиць, і одна пропозиція, яку я бачив, - це використовувати розділений вид, завдяки якому велика таблиця розбивається на ряд менших «розділених» таблиць.

1 , 2 , 3 , 4

Тестуючи цей підхід, я виявив щось, що не має для мене великого сенсу. Коли я фільтрую "стовпчик розподілу" на перегляді фактів, оптимізатор шукає лише відповідні таблиці. Крім того, якщо я фільтрую цей стовпець таблиці вимірів, оптимізатор видаляє непотрібні таблиці.

Однак якщо я фільтрую інший аспект вимірювання, оптимізатор шукає PK / CI кожної базової таблиці.

Ось такі запити:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];

Факт фільтра на ключ

тьмяний фільтр на клавіші

тьмяний фільтр в аспекті

Ось посилання на сеанс провідника SQL Plan Explorer.

Я працюю над тим, щоб насправді розділити більшу таблицю, щоб побачити, чи отримаю я усунення розділів, щоб відповісти аналогічно.

Я отримую розділ для (простого) запиту, який фільтрує в аспекті виміру.

Тим часом, ось лише статистика копії бази даних:

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

"Старий" оцінювач кардинальності отримує менш дорогий план, але це через менші оцінки кардинальності для кожної з (непотрібних) індексів.

Мені хотілося б знати, чи існує спосіб отримати оптимізатор використовувати стовпчик ключів під час фільтрації за іншим аспектом виміру, щоб він міг усунути пошуки в невідповідних таблицях.

Версія SQL Server:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

Просто FYI .. останній потік статистики пошкодженийCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Кін Шах

Схоже, сценарій для бази даних лише для статистики усічений. Я спробував натиснути "переглянути весь файл" і завантажити ZIP, але в будь-якому випадку я не маю статистики для ObservationDatesтаблиці. Я не отримую такого ж плану, як Павло, навіть з 4199, і я думаю, що саме тому.
Джефф Паттерсон

@GeoffPatterson це працює для мене. Ви натискали на посилання на неочищений файл? gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/…, проте, як зазначив Кін, останній потік статистики пошкоджений: /
swasheck

Я натиснув посилання на необроблений файл. Сценарій працює (крім проблеми, яку зазначив Кін), але не містить логіки для створення статистики ObservationDates. Я закінчив працювати UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000вручну, щоб отримати план, який демонстрував Пол.
Джефф Паттерсон

дивно. створивши нову базу даних і запустивши цей скрипт, у мене є об'єкти статистики (ну, вони індекси), ObservationDatesтому я не впевнений, що з цим відбувається. Крім того, я не в змозі отримати згенерований паул плану також. Я спробую переглянути оновлення.
сварка

Відповіді:


10

Увімкнути прапор сліду 4199.

Я також повинен був видати:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

щоб отримати плани, показані нижче. Статистика для цієї таблиці відсутня для завантаження. Цифра 73,049 походить з інформації про кардинальність таблиці в додатку Провідник плану. Я використовував SQL Server 2014 SP1 CU4 (збірка 12.0.4436) з двома логічними процесорами, максимальною пам’яттю, встановленою на 2048 МБ, та відсутніми прапорцями слідів, крім 4199.

Потім слід отримати план виконання, який містить динамічне усунення розділів:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);

Фрагмент плану:

Фрагмент плану

Це може виглядати гірше, але "Фільтри" - це всі фільтри старту . Приклад предиката:

Властивості фільтра

Під час ітерації циклу предикат предикату тестується, і лише якщо він повертає значення true, виконаний Clustered Index Seek під ним. Отже, динамічне усунення розділів.

Це, можливо , НЕ зовсім так ефективно , як статична ліквідація, особливо якщо план паралельно.

Можливо , вам доведеться спробувати натяки , як MAXDOP 1, FAST 1або FORCESEEKуявлення , щоб отримати той же план. Вибір витрат на оптимізатор з виборами з розділеними переглядами (як-от секціоновані таблиці) може бути складним.

Суть у тому, що вам потрібен план, який містить пускові фільтри, щоб отримати динамічне усунення розділів із розділеними представленнями.


Запити із вбудованими USE PLANпідказками: (через gist.github.com):


1
Чудова інформація, дякую Пол! Мені було цікаво, коли я написав свою відповідь, чому не існує способу SQL Server зробити такий тип усунення. Виявляється, я просто цього раніше не бачив!
Джефф Паттерсон

6

Моє зауваження завжди полягало в тому, що ви повинні вказати значення (або діапазон значень) для стовпця розділу чітко у запиті, щоб отримати "усунення таблиці" в розділі перегляду. Це ґрунтується на досвіді використання розділених представлень у виробництві від SQL Server 2000 до SQL Server 2014.

SQL Server не має поняття оператора приєднання до циклу, в якому двигун може динамічно націлювати пошук безпосередньо на відповідну таблицю на внутрішній стороні циклу, виходячи зі значення рядка на зовнішній стороні циклу. Однак, як пояснюється у відповіді Поля , існує можливість складання плану з фільтрами для запуску з метою динамічного пропускання невідповідних таблиць на внутрішній стороні циклу в постійний час (на відміну від логарифмічного шляхом фактичного виконання пошуку).

Зауважте, що для розділених таблиць підтримується цей тип пошуку (до певного розділу).

Якщо ви вирішили використовувати розділені представлення, ще один варіант - розділити ваш запит на кілька запитів, наприклад:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)

Це дає наступний план. Зараз є додатковий запит, який потрапляє в таблицю вимірів, але запит над (імовірно набагато більшою) таблицею фактів оптимізований.

введіть тут опис зображення


Такий же ефект був би досягнутий, якби ви включили перший запит у другий, не звертаючись до змінних?
Андрій М

@AndriyM Якщо я вас правильно зрозумів, відповідь "ні", такого ж ефекту не буде досягнуто, і план запитів торкнеться всіх таблиць у розділі перегляду, якщо ви спробуєте поєднати два запити. Якщо ви повинні виконати перший запит, а потім вставити значення 20000101і 20051231замість змінних (або зробити щось подібне за допомогою двох окремих запитів у вашій програмі), то так, такий же ефект був би досягнутий без використання змінних.
Джефф Паттерсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.