Ориентировочная стоимость поддерева, ужасная оптимизация - PullRequest
2 голосов
/ 06 июля 2010

Я присоединяюсь к таблице, имеющей два поля идентификатора записи (record1, record2), к представлению дважды - один раз для каждой записи - и выбираю верхнюю 1000. Представление состоит из нескольких довольно больших таблиц и его поля idявляется конкатенацией строк их соответствующих идентификаторов (это было необходимо для некоторых сторонних программ, которым для представления требуется уникальный идентификатор. Нумерация строк была крайне медленной).Также в представлении есть предложение where, вызывающее функцию, сравнивающую даты.

Предполагаемый план выполнения выдает предупреждение «Нет предиката соединения», если я не использую OPTION (FORCE ORDER).При форсировании заказа план выполнения имеет несколько узлов, отображающих 100% стоимости.В обоих случаях оценочная стоимость поддерева в конечной точке на тринадцать порядков меньше, чем просто один из его узлов (он выполняет лот или объединение вложенных циклов с затратами на процессор, например 35927400000000)

Что здесь происходит с числами в плане выполнения?И почему SQL Server так сложно оптимизировать запрос?

Простое добавление индекса к представлению каскадной строки и использование подсказки таблицы NOEXPAND полностью устранило проблему.Это продолжалось всего 12 секунд.Но почему sql споткнулся так плохо (даже требуя подсказку noexpand после того, как я добавил индекс)?

Запуск SQL Server 2008 SP1 с CU 8.

Представление:

SELECT
    dbo.fnGetCombinedTwoPartKey(N.NameID,A.AddressID) AS NameAddressKey,
    [other fields]

FROM     
    [7 joined tables]
WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1

Запрос

SELECT TOP 1000
    vw1.strFullName,
    vw1.strAddress1,
    vw1.strCity,
    vw2.strFullName,
    vw2.strAddress1,
    vw2.strCity
FROM tblMatches M
JOIN vwImportNameAddress vw1 ON vw1.NameAddressKey = M.Record1 
JOIN vwImportNameAddress vw2 ON vw2.DetailAddressKey = M.Record2 

Ответы [ 2 ]

1 голос
/ 07 июля 2010

Похоже, вы уже достаточно близки к объяснению. Это из-за этого:

Представление состоит из нескольких довольно больших таблиц, и его поле id представляет собой строку строк их соответствующих идентификаторов ...

Это создает условие предиката необязательного соединения и не позволяет SQL-серверу использовать какие-либо индексы в базовых таблицах. Таким образом, движок должен выполнить полное сканирование всех базовых таблиц для каждого объединения (в вашем случае две).

Возможно, чтобы избежать нескольких полных сканирований таблиц (по одному для каждой таблицы, умноженных на количество объединений), SQL Server решил, что быстрее будет просто использовать декартово произведение и фильтровать впоследствии (отсюда и «нет». предикат присоединения «предупреждение». Когда вы FORCE ORDER, он покорно выполняет все полные сканирования и вложенные циклы, которые вы изначально запрашивали.

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


Редактировать: я также пропустил это при первом прочтении:

WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1

Опять же, это предикат без аргументов, который приведет к снижению производительности. Обтекание любых столбцов в UDF вызовет такое поведение. Индексирование представления также материализует его, что также может влиять на скорость запроса; без индекса этот предикат должен оцениваться каждый раз и вызывать полное сканирование базовых таблиц, даже без составного идентификатора.

1 голос
/ 07 июля 2010

Это должно было бы проанализировать вашу функцию (fnGetCombinedTwoPartKey), чтобы определить, какие столбцы выбираются для создания столбца результата. Это не может, поэтому предполагается, что все столбцы необходимы. Если ваши индексы покрывают индексы, то ваша оценка будет неправильной.

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