Почему помещение выражения WHERE вне вида имеет ужасную производительность - PullRequest
16 голосов
/ 11 июля 2011

Допустим, у вас есть представление:

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 раз больше времени, чем код, в который я копирую и вставляю логику представления.

Есть идеи?

Ответы [ 5 ]

16 голосов
/ 11 июля 2011

Это называется " Predicate pushing ", иначе говоря, отложенная фильтрация.

SQL Server не всегда понимает, ГДЕ можно применить "раньше", эффективно внутри представления.

В SQL Server 2008 было смягчено, чтобы работать больше, чем ожидалось

2 голосов
/ 11 июля 2011

синтаксис OVER () был совершенно новым в SS2005 и, видимо, плохо интегрирован в оптимизатор.Я предлагаю вам попробовать более традиционное выражение?Вероятно, НЕ является выражением, если вы заботитесь об оптимизации.

http://www.sqlteam.com/article/sql-sever-2005-using-over-with-aggregate-functions

Или, что еще лучше, познакомьтесь немного с профилировщиком - представление должно быть исправимо.

2 голосов
/ 11 июля 2011

Я не эксперт по SQL, поэтому меня могут отвергнуть за мою глупость, но я предполагаю, что в первом случае SQL извлекает результаты представления whole перед применением предиката вГДЕ оговорка.Поэтому, когда вы запрашиваете представление, оно выбирает все записи, помещает их в память, а затем применяет фильтр Date после того, как это сделано.

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

Если представления не обрабатываются по-разному.

1 голос
/ 11 июля 2011

Технически, вы не сравниваете одни и те же операторы SQL. По вашему мнению, он возвращает a.date, a.Col1, b.Col2, плюс вашу функцию DENSE_RANK (). В вашем запросе без представления вы возвращаете все столбцы.

Сначала вы можете подумать, что возвращать все столбцы было бы хуже. Но трудно определить, что было бы лучше, не зная, как выглядит структура таблицы, включая индексы.

Сравнивали ли вы планы запросов для каждого оператора?

0 голосов
/ 11 июля 2011

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

...