В этой статье речь пойдет об адаптивном соединении. Сначала я приведу пример ущербности классического повторного использования плана с зависимыми от параметров запросами. Затем мы посмотрим, как можно решить проблему с помощью адаптивного соединения. Кроме того, я поясню, как включить адаптивное соединение по строчному хранилищу, rowstore, несмотря на то обстоятельство, что формально в первой реализации эта функция поддерживается только как оператор пакетного режима по хранилищу столбцов, columnstore.

Версия SQL Server 2017 CTP 2.0 дополнена поддержкой адаптивной обработки запросов. Традиционно оптимизатор запросов обрабатывает все варианты плана перед выполнением запроса, и SQL Server не мог этого изменить во время выполнения. Благодаря адаптивной обработке запросов SQL Server может динамически адаптировать варианты оптимизации к условиям выполнения, в частности к неверным оценкам кратности.

В первую группу улучшений входят обратная связь для адаптивного предоставления памяти в пакетном режиме (https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/11/29/introducing-batch-mode-adaptive-memory-grant-feedback/), адаптивное соединение в пакетном режиме (https://blogs.msdn.microsoft.com/sqlserverstorageengine/

2017/04/19/introducing-batch-mode-adaptive-joins/) и выполнение с чередованием для многооператорных функций, возвращающих табличное значение (https://blogs.msdn.microsoft.com/sqlserverstorageengine/2017/04/19/introducing-interleaved-execution-for-multi-statement-table-valued-functions/). Все они прекрасно описаны специалистом Microsoft Джо Сэком.

Зависимые от параметров запросы соединения

Типичная ситуация: имеется хранимая процедура с зависимым от параметров запросом с соединением; SQL Server оптимизирует запрос для значения полученного параметра и кэширует план. Оптимизатору предстоит сделать выбор между классическим циклом и алгоритмом хеш-соединения (предположим, для слияния условия недостаточны) на основе оценки кратности для внешнего входа соединения. При малом числе внешних строк обычно оптимален циклический алгоритм. Сверх определенного порога оптимален алгоритм хеширования. В любом случае оптимизатор обрабатывает полученное значение параметра, когда оптимизирует запрос, и этот план кэшируется и используется повторно, пока не произойдет событие перекомпиляции, даже если процедура выполняется регулярно с различными входными значениями.

Чтобы продемонстрировать это, я создам хранимую процедуру в тестовой базе данных PerformanceV3. Вы можете загрузить исходный код, чтобы создать тестовую базу данных, по адресу: http://tsql.solidq.com/SampleDatabases/PerformanceV3.zip.

Я использую зависимый от параметров запрос в своей хранимой процедуре, он приведен в листинге 1.

Пользователь передает префикс для имени клиента и диапазон даты в качестве входных данных и получает заказы, размещенные клиентами с указанным префиксом в имени компании в течение указанного периода.

Исходя из того, что вы не намерены использовать индекс хранилища столбцов для этих таблиц, подумайте, какими будут оптимальные индексы rowstore для данного запроса. Оптимальный индекс для Customers — индекс с ключом custname (для поддержки фильтра) и включенным столбцом custid (для охвата). Выбор рекомендуемой индексации для Orders зависит от числа подходящих клиентов. Если их мало, оптимальным будет алгоритм с вложенными циклами. Индекс с custid и orderdate формирует список ключей индекса (для поддержки предикатов соединения и фильтра) и включение orderid, empid, shipperid (для охвата). При большом числе подходящих заказчиков идеальным будет алгоритм соответствия хеша Hash Match. Индекс с ключом orderdate (поддержка фильтра диапазона дат) и включение остальных столбцов из Orders (для охвата).

Таблица Orders уже имеет кластеризованный индекс с ключом orderdate. Выполните программный код листинга 2, чтобы...

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

Поделитесь материалом с коллегами и друзьями

Купить номер с этой статьей в PDF