Использование подсказок в запросах INDEX и FORCESEEK в структурах планов
Можно указать табличные подсказки INDEX и FORCESEEK в качестве подсказок в запросе. При указании их как подсказок в запросе они ведут себя так же, как и встроенные табличные подсказки или подсказки представлений.
Подсказка INDEX вынуждает оптимизатор запросов использовать только указанные индексы для доступа к данным упоминаемой таблицы или упоминаемого представления в запросе. Подсказка FORCESEEK вынуждает оптимизатор запросов использовать только операцию поиска по индексу для доступа к данным ссылочной таблицы или ссылочного представления в запросе. Эти подсказки можно использовать в предложении OPTION структуры плана, чтобы оптимизировать запрос. Если запрос совпадает со структурой плана, предложение OPTION, указанное в структуре плана, добавляется к запросу прежде, чем запрос подвергается компиляции и оптимизации. Дополнительные сведения о структурах плана см. в разделе Основные сведения о структурах планов.
Внимание! |
---|
Структуры планов с неправильным использованием подсказок в запросе могут привести к проблемам при компиляции во время выполнения и к ухудшению производительности. Структуры планов должны применяться только опытными разработчиками и администраторами баз данных. |
Табличные подсказки INDEX и FORCESEEK, указанные в качестве подсказки в запросе, допустимы для следующих объектов:
Таблицы
Представления
Индексированные представления
Обобщенные табличные выражения (подсказку необходимо указывать в инструкции SELECT, результирующий набор которой заполняет обобщенное табличное выражение).
Динамические административные представления
Именованные вложенные запросы
Табличные подсказки не могут быть указаны для возвращающих табличное значение функций, переменных таблицы или инструкций OPENROWSET.
Чтобы указать подсказку индекса для индексированного представления, в предложении OPTION также должна быть указана подсказка NOEXPAND, иначе подсказка индекса будет пропущена. Дополнительные сведения см. в разделе Разрешение индексов для представлений.
Дополнительные сведения о синтаксисе, используемом для указания подсказок INDEX и FORCESEEK в качестве подсказок в запросе, см. в разделе Подсказки в запросах (Transact-SQL).
Рекомендации
Рекомендуются следующие методы:
Подсказки INDEX и FORCESEEK следует использовать в качестве подсказок в запросе только в контексте структуры плана или в нерегламентированных запросах при проверке инструкций структуры плана. Для всех других нерегламентированных запросов эти подсказки следует указывать как табличные подсказки.
Перед использованием подсказки FORCESEEK следует убедиться, что статистика базы данных актуальна и точна.
Актуальная статистика позволяет оптимизатору точно оценить стоимость разных планов запросов и выбрать высококачественный план. Поэтому рекомендуется установить параметры AUTO_CREATE_STATISTICS и AUTO_UPDATE_STATISTICS в значение ON (по умолчанию) для каждой пользовательской базы данных. Также можно вручную обновить статистику по таблице или представлению с помощью инструкции UPDATE STATISTICS.
Не используйте без необходимости подсказку INDEX в сочетании с FORCESEEK. То есть, если использование только подсказок FORCESEEK позволяет сформировать пригодный план, то параллельное использование подсказок INDEX может слишком сократить возможности оптимизатора. Кроме того, подсказка INDEX приведет к завершению запроса с ошибкой в случае, если физическая схема таблицы была изменена с целью удаления индекса, на который ссылается подсказка. Напротив, если в таблице, к которой применяется подсказка FORCESEEK, существует по крайней мере один доступный для использования индекс, запрос будет компилироваться даже в процессе изменения структур индекса.
Не используйте подсказку INDEX (0) вместе с подсказкой FORCESEEK. Подсказка INDEX (0) запускает принудительный просмотр базовой таблицы. При использовании с подсказкой FORCESEEK план не находится и возвращается ошибка 8622.
Не используйте подсказку в запросе USE PLAN вместе с подсказкой FORCESEEK. Подсказка FORCESEEK в этом случае не будет обрабатываться.
Совместное использование подсказок INDEX и FORCESEEK с другими табличными подсказками
Подсказки INDEX и FORCESEEK могут быть указаны для запроса, который не имеет существующих табличных подсказок. Кроме того, ими можно заменить одну или несколько уже существующих подсказок INDEX или FORCESEEK в этом запросе. Если в запросе, сопоставленном со структурой плана, уже присутствует предложение WITH, указывающее табличные подсказки, то подсказки в запросе, указанные в параметре @hints структуры плана, заменяют аналогичные в этом запросе. Например, если запрос содержит табличную подсказку WITH INDEX (PK_Employee_EmployeeID) для таблицы HumanResources.Employee, а параметр @hints в структуре плана задает OPTION (TABLE HINT ( HumanResources.Employee, INDEX( IX_Employee_ManagerID ) ), оптимизатор запросов будет использовать индекс IX_Employee_ManagerID.
Табличные подсказки, отличные от INDEX и FORCESEEK, запрещено применять в качестве подсказок в запросе в структуре плана, за исключением запросов, в которых уже есть предложение WITH, указывающее табличную подсказку. В этом случае, чтобы сохранить семантику запроса, необходимо также указать соответствующую табличную подсказку в качестве подсказки в запросе, задав в предложении OPTION ключевое слово TABLE HINT. Например, если запрос содержит табличную подсказку NOLOCK, предложение OPTIONS в параметре @hints структуры плана также должно содержать подсказку NOLOCK, наряду с любой табличной подсказкой INDEX или FORCESEEK. См. пример В далее в этом разделе. Если указать табличную подсказку, отличную от INDEX или FORCESEEK, с использованием TABLE HINT в предложении OPTION без совпадающей подсказки в запросе (или наоборот), то будет возвращена ошибка 8702, сигнализирующая, что предложение OPTION может вызвать изменение в семантике запроса и запрос завершится с ошибкой.
Совместное использование подсказок INDEX и FORCESEEK с другими подсказками в запросе
Если в запросе, сопоставленном со структурой плана, уже присутствует предложение OPTION, указывающее подсказки в запросе, то подсказки в запросе, указанные в параметре @hints структуры плана, заменяют аналогичные в запросе. Чтобы структура плана совпала с запросом, уже содержащим предложение OPTION, необходимо включить предложение OPTION запроса при указании текста запроса для сопоставления в инструкции sp_create_plan_guide (Transact-SQL). Если необходимо, чтобы подсказки, указанные в структуре плана, были добавлены к подсказкам, которые уже существуют в запросе, вместо того, чтобы заменить их, следует указать и исходные, и дополнительные подсказки в предложении OPTION структуры плана.
Примеры
А. Использование подсказок FORCESEEK
В следующем примере в параметре @hints структуры плана используется подсказка FORCESEEK. Этот параметр вынуждает оптимизатор запросов использовать для доступа к данным таблицы HumanResources.Employee только операцию поиска по индексу. Следует заметить, что это может вынудить оптимизатор использовать индекс, отличный от указанного в табличной подсказке.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide3',
@stmt = N'SELECT c.LastName, c.FirstName, HumanResources.Employee.Title
FROM HumanResources.Employee
JOIN Person.Contact AS c ON HumanResources.Employee.ContactID = c.ContactID
WHERE HumanResources.Employee.ManagerID = 3
ORDER BY c.LastName, c.FirstName;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT( HumanResources.Employee, FORCESEEK))';
GO
Б. Использование нескольких табличных подсказок
В следующем примере к одной таблице применяется подсказка INDEX, а к другой — подсказка FORCESEEK.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide4',
@stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT ( e, INDEX( IX_Employee_ManagerID ) )
, TABLE HINT ( c, FORCESEEK) )';
GO
В. Указание подсказок, изменяющих семантику
В следующем примере запрос содержит две табличные подсказки: NOLOCK, которая изменяет семантику, и INDEX, которая не изменяет семантику. Чтобы сохранить семантику запроса, подсказка NOLOCK указывается в предложении OPTIONS структуры плана. Помимо подсказки NOLOCK, указываются подсказки INDEX и FORCESEEK, которые замещают не изменяющую семантику подсказку INDEX в запросе, когда инструкция компилируется и оптимизируется.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide6',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT ( e, INDEX( IX_Employee_ManagerID) , NOLOCK, FORCESEEK ))';
GO
В следующем примере показывается альтернативный метод сохранения семантики запроса, который также позволяет оптимизатору выбирать индекс, отличный от индекса, указанного в табличной подсказке. Это делается путем указания подсказки NOLOCK в предложении OPTIONS (поскольку она изменяет семантику) и указания ключевого слова TABLE HINT только со ссылкой на таблицу, без подсказки INDEX.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide7',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 2;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT ( e, NOLOCK))';
GO
Г. Использование конструкции TABLE HINT для замещения существующей табличной подсказки
В следующем примере показывается использование конструкции TABLE HINT без указания подсказки INDEX для замещения поведения табличной подсказки INDEX, указанной в предложении FROM запроса. Этот метод позволяет оптимизатору выбрать индекс, отличный от указанного в табличной подсказке.
USE AdventureWorks;
GO
EXEC sp_create_plan_guide
@name = N'Guide5',
@stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e WITH (INDEX (IX_Employee_ManagerID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT(e))';
GO