Можно ли заставить оптимизатор исключить ненужные таблицы в этом многораздельном представлении?


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 Sentry 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)

Просто к вашему сведению .. последний поток статистики поврежден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так что я не уверен, что с этим происходит. Кроме того, я также не могу получить план Пола. Я попробую обновление, чтобы увидеть.
swasheck

Ответы:


10

Включить флаг трассировки 4199.

Я также должен был выпустить:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

чтобы получить планы, показанные ниже. Статистика по этой таблице отсутствовала при загрузке. Число 73 049 было получено из информации о количестве элементов таблицы в приложении Plan Explorer. Я использовал SQL Server 2014 с пакетом обновления 1 (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, выполняется поиск кластеризованного индекса ниже его. Следовательно, устранение динамических разделов.

Это, возможно , не совсем так эффективно , как статическая ликвидация, особенно если план параллельно.

Возможно, вам придется попробовать подсказки, например 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.