«Query Hints» в документации переводится как «указания запросов», кто-то называет их «подсказками», но чаще говорят просто «хинты». Я буду использовать в заметке именно последнее выражение, т.к. оно более распространено в повседневной жизни и сразу дает понять, о чем идет речь. Эта публикация — введение, она открывает цикл заметок по новым хинтам, которые появились в SQL Server 2016 SP1.
Существуют разные мнения по поводу использования хинтов в запросах от «никогда их не используйте» до «если что-то работает плохо, все решается хинтом».
Я придерживаюсь мнения, что хинт – это прежде всего инструмент, и, если его использовать к месту, то он может быть полезен, если же использовать его бездумно, то может навредить. В своей практике я прибегаю к хинтам при соблюдении двух условий. Первое – мне полностью понятна причина плохого плана, второе – других способов устранить эту причину нет.
Кроме того, важно помнить, что хинты, в плане ограничения свободы оптимизатора, бывают более жесткие и менее жесткие. По возможности, лучше использовать менее жесткие. Например, для ограничения типов соединений, лучше использовать хинт запроса, чем хинт в соединении, т.к. последний ограничивает еще и порядок соединений.
Хинтов запроса существует довольно много, но мы остановимся на тех, что появились в SQL Server 2016 SP1, и которые можно использовать при помощи ключевого слова USE HINT. Они могут быть получены при помощи нового представления sys.dm_exec_valid_use_hints. Ниже приведена таблица доступных хинтов с кратким описанием.
Hint | Описание | TF |
DISABLE_OPTIMIZED_NESTED_LOOP | Отключает оптимизацию batch sort в соединении вложенными циклами | 2340* |
FORCE_LEGACY_CARDINALITY_ESTIMATION | Включает «старый» механизм оценки (версия 70, применялся до SQL Server 2014) | 9481 |
ENABLE_QUERY_OPTIMIZER_HOTFIXES | Включить исправления оптимизатора | 4199 |
DISABLE_PARAMETER_SNIFFING | Отключить прослушивание параметров | 4136 |
ASSUME_MIN_SELECTIVITY_FOR_FILTER_ESTIMATES | При оценке комплексных предикатов использовать предположение минимальной селективности | 4137 (<2014) 9471 (>=2014) |
ASSUME_JOIN_PREDICATE_DEPENDS_ON_FILTERS | Включает зависимость селективности соединения от предикатов по таблицам | 9476 |
ENABLE_HIST_AMENDMENT_FOR_ASC_KEYS | Включить автоматическое дополнение гистограммы статистики при оценке предиката по колонке, вне зависимости возрастания/убывания ее значений | 4139 |
DISABLE_OPTIMIZER_ROWGOAL | Отключить механизм учета целевого числа строк при построении плана запроса | 4138 |
FORCE_DEFAULT_CARDINALITY_ESTIMATION | Установить версию модели оценки, соответствующую уровню совместимости БД |
Чтобы применить хинт к запросу, необходимо в предложении OPTION указать ключевое слово USE HINT и в скобках перечислить один или несколько хинтов, например:
select name from sys.all_columns option( use hint( 'FORCE_LEGACY_CARDINALITY_ESTIMATION', 'ENABLE_QUERY_OPTIMIZER_HOTFIXES' ) );
Многое из того что позволяют делать хинты USE HINT было ранее доступно при помощи флагов трассировки, они перечислены в последнем столбце таблицы. Минус подходов с флагами это – слабая самодокументированность (нужно помнить, какой номер флага за что отвечает), и необходимость привилегий SA, и, хотя для последнего есть обходной путь, это не очень удобно.
Из краткого описания в документации может быть трудно понять, на что влияют эти хинты, поэтому, в дальнейших заметках, мы разберем что означает каждый из них и как он влияет на план запроса.
В следующей заметке, мы поговорим про хинт DISABLE_OPTIMIZED_NESTED_LOOP.