Ответ 1
Он называется " Predicate pushing" aka отложенная фильтрация.
SQL Server не всегда понимает, что WHERE можно применять "раньше", в представлении эффективно.
В SQL Server 2008 было смягчено больше, чем ожидалось
Скажем, у вас есть представление:
CREATE VIEW dbo.v_SomeJoinedTables AS
SELECT
a.date,
a.Col1,
b.Col2,
DENSE_RANK()
OVER(PARTITION BY a.date, a.Col2 ORDER BY a.Col3) as Something
FROM a JOIN b on a.date = b.date
Я обнаружил, что производительность:
SELECT *
FROM v_SomeJoinedTables
WHERE date > '2011-01-01'
намного хуже, чем
SELECT *,
DENSE_RANK()
OVER(PARTITION BY a.date, a.Col2 ORDER BY a.Col3) as Something
FROM a JOIN b ON a.date = b.date
WHERE a.date > '2011-01-01'
Я очень удивлен тем, что план запросов для этих двух операторов не является тем же.
Я также попытался использовать встроенную функцию с табличной оценкой, но запрос все еще занимает 100-1000 раз дольше, чем код, в котором я копирую и вставляю логику представления.
Любые идеи?
Он называется " Predicate pushing" aka отложенная фильтрация.
SQL Server не всегда понимает, что WHERE можно применять "раньше", в представлении эффективно.
В SQL Server 2008 было смягчено больше, чем ожидалось
Я не эксперт по SQL, поэтому мне может быть отказано в моей глупости, но я предполагаю, что в первом случае SQL извлекает результаты представления целиком перед применением предиката в предложении WHERE. Поэтому, когда вы запрашиваете представление, он выбирает все записи, помещает их в память и затем применяет фильтр даты после его завершения.
Это похоже на то, как весь набор данных, указанный в ваших соединениях, извлекается до применения фильтра в WHERE (урок здесь заключается в том, что вы должны применять предикаты в своем предложении ON, когда это возможно).
Если взгляды не обрабатываются по-разному.
синтаксис OVER() был совершенно новым в SS2005 и, по-видимому, не был хорошо интегрирован в оптимизатор. Я предлагаю вам попробовать более традиционное выражение? Вероятно, это НЕ выражение, если вы заботитесь об оптимизации.
http://www.sqlteam.com/article/sql-sever-2005-using-over-with-aggregate-functions
Или, лучше, познакомьтесь с профилировщиком - представление должно быть исправлено.
Технически вы не сравниваете одни и те же операторы SQL. Ваше представление указывает, что оно возвращает a.date, a.Col1, b.Col2,
плюс функцию DENSE_RANK(). В запросе без представления вы возвращаете все столбцы.
Сначала вы можете подумать, что возврат всех столбцов будет хуже. Но трудно определить, что было бы лучше, не зная, как выглядит структура таблицы, включая индексы.
Вы сравнили планы запросов для каждого утверждения?
В качестве рабочего решения я бы предложил использовать функцию вместо представления, чтобы вы могли передавать параметр данных.