Эквивалентен ли этот запрос SQL Server 2008 OPTIMIZE FOR UNKNOWN? - PullRequest
11 голосов
/ 09 февраля 2010

Я поддерживаю хранимые процедуры для SQL Server 2005 и хотел бы использовать новую функцию в 2008 году, которая позволяет подсказку запроса: «ОПТИМИЗИРОВАТЬ ДЛЯ НЕИЗВЕСТНО»

Похоже, что следующий запрос (написанный для SQL Server 2005) оценивает такое же количество строк (то есть селективность), как если бы был указан OPTION (OPTIMIZE FOR UNKNOWN):

CREATE PROCEDURE SwartTest(@productid INT)
AS  
DECLARE @newproductid INT
SET @newproductid = @productid

SELECT ProductID 
FROM Sales.SalesOrderDetail 
WHERE ProductID = @newproductid

Этот запрос позволяет избежать перехвата параметров путем объявления и установки новой переменной. Действительно ли это обходной путь SQL Server 2005 для функции OPTIMIZE-FOR-UNKNOWN? Или я что-то упустил? (Официальные ссылки, ответы или результаты испытаний приветствуются).

Подробнее: Быстрый тест на SQL Server 2008 говорит мне, что число оценочных строк в этом запросе фактически такое же, как если бы было указано OPTIMIZE FOR UNKNOWN. Это то же самое поведение на SQL Server 2005? Мне кажется, я помню, как однажды услышал, что без дополнительной информации механизм оптимизации SQL Server должен угадать селективность параметра (обычно 10% для предикатов неравенства). Я все еще ищу точную информацию о поведении SQL 2005, хотя. Я не совсем уверен, что информация существует, хотя ...

Подробнее 2: Чтобы было ясно, этот вопрос требует сравнения подсказки НЕИЗВЕСТНОГО запроса и метода маскировки параметров, который я описываю.

Это технический вопрос, а не вопрос решения проблемы. Я рассмотрел множество других вариантов и остановился на этом. Поэтому единственной целью этого вопроса было помочь мне обрести уверенность в том, что оба метода эквивалентны.

Ответы [ 4 ]

4 голосов
/ 09 февраля 2010

Я использовал это решение несколько раз в последнее время, чтобы избежать перехвата параметров в SQL 2005, и мне кажется, что он делает то же самое, что OPTIMIZE FOR UNKNOWN в SQL 2008. Оно исправило множество проблем, которые мы имели с некоторыми из наших больших хранимые процедуры иногда просто зависают при передаче определенных параметров.

4 голосов
/ 10 февраля 2010

Хорошо, я провел несколько экспериментов. Я напишу результаты здесь, но сначала я хочу сказать, что исходя из того, что я видел и знаю, я уверен, что с использованием временных параметров в 2005 и 2008 годах точно эквивалентно использовать ОПТИМИЗАЦИЮ 2008 ДЛЯ НЕИЗВЕСТНО . По крайней мере, в контексте хранимых процедур.

Так вот что я нашел. В вышеописанной процедуре я использую базу данных AdventureWorks. (Но я использую аналогичные методы и получаю похожие результаты для любой другой базы данных) Я запустил:

dbcc show_statistics ('Sales.SalesOrderDetail', IX_SalesOrderDetail_ProductID) 

И я вижу статистику с 200 шагами в гистограмме. Глядя на его гистограмму, я вижу, что есть 66 различных строк диапазона (то есть 66 различных значений, которые не были включены в статистику как значения равенства). Добавьте 200 строк равенства (с каждого шага), и я получу оценку 266 различных значений для ProductId в Sales.SalesOrderDetail.

Имея 121317 строк в таблице, я могу оценить, что каждый ProductId имеет в среднем 456 строк. И когда я смотрю на план запроса для моей процедуры тестирования (в формате xml), я вижу что-то вроде:

...
<QueryPlan DegreeOfParallelism="1"  >
  <RelOp NodeId="0" 
         PhysicalOp="Index Seek" 
         LogicalOp="Index Seek" 
         EstimateRows="456.079" 
         TableCardinality="121317"  />
    ...
  <ParameterList>
    <ColumnReference 
      Column="@newproductid" 
      ParameterRuntimeValue="(999)" />
  </ParameterList>
</QueryPlan>
...       

Итак, я знаю, откуда берется значение EstimateRows (с точностью до трех десятичных знаков), и обратите внимание, что атрибут ParameterCompiledValue отсутствует в плане запроса. Именно так выглядит план при использовании OPTIMIZE FOR UNKNOWN 2008 года

1 голос
/ 09 февраля 2010

Интересный вопрос.

В блоге группы разработчиков SQL и программиста API есть хорошая статья здесь , в которой перечислены обходные решения, предшествующие SQL 2008:

  1. используйте подсказку RECOMPILE, чтобы запрос каждый раз перекомпилировался
  2. без параметров запроса
  3. указать конкретные значения в ОПТИМИЗАЦИИ ЗАПРОСОВ
  4. принудительное использование определенного индекса
  5. используйте план плана

Что приводит меня к этой статье , в которой упоминается ваш обходной путь использования локальных параметров и как он генерирует план выполнения на основе статистики. Насколько этот процесс похож на новый ОПТИМИЗАТОР ДЛЯ НЕИЗВЕСТНОЙ подсказки, я не знаю. Я догадываюсь, что это разумный обходной путь.

0 голосов
/ 10 февраля 2010

Я использовал эту технику маскирования параметров, по крайней мере, в прошлом году, потому что из-за странных проблем с производительностью, и она работала хорошо, но ОЧЕНЬ раздражает необходимость делать это все время.

Я ТАКЖЕ использовал WITH RECOMPILE.

У меня нет контролируемых тестов, потому что я не могу выборочно включать и отключать использование каждого из них в системе автоматически, но я подозреваю, что маскирование параметра только поможет ЕСЛИ параметр используется. У меня есть несколько сложных SP, где параметр не используется в каждом операторе, и я ожидаю, что WITH RECOMPILE все еще был необходим, потому что некоторые из «временных» рабочих таблиц не заполнены (или даже проиндексированы одинаково, если я пытаюсь настроить ) одинаково при каждом запуске, и некоторые более поздние операторы не полагаются на параметр, если рабочие таблицы уже заполнены соответствующим образом. Я разбил некоторые процессы на несколько SP точно, чтобы можно было должным образом проанализировать и выполнить работу, выполненную для заполнения рабочей таблицы в одном SP, для WITH RECOMPILE в следующем SP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...