В этом превосходном вопросе SO различия между CTE
и sub-queries
были обсуждены.
Я хотел бы специально спросить:
При каких обстоятельствах каждое из следующих действий более эффективно / быстрее?
- КТР
- Sub-запросы
- Временный стол
- Переменная таблицы
Традиционно я использовал много temp tables
в разработке stored procedures
- так как они кажутся более читабельными, чем множество переплетенных подзапросов.
Non-recursive CTE
s очень хорошо инкапсулируют наборы данных и очень удобочитаемы, но есть ли конкретные обстоятельства, когда можно сказать, что они всегда будут работать лучше? или дело в том, что приходится постоянно искать разные варианты, чтобы найти наиболее эффективное решение?
РЕДАКТИРОВАТЬ
Мне недавно сказали, что с точки зрения эффективности, временные таблицы являются хорошим первым выбором, поскольку они имеют связанную гистограмму, то есть статистику.
Ответы:
SQL является декларативным языком, а не процедурным языком. То есть вы создаете оператор SQL для описания желаемых результатов. Вы не говорите движку SQL, как выполнять работу.
Как правило, желательно, чтобы механизм SQL и оптимизатор SQL нашли лучший план запроса. На разработку движка SQL уходит много человеко-лет, поэтому позвольте инженерам делать то, что они умеют.
Конечно, бывают ситуации, когда план запроса не является оптимальным. Затем вы хотите использовать подсказки запроса, реструктурировать запрос, обновлять статистику, использовать временные таблицы, добавлять индексы и т. Д., Чтобы повысить производительность.
Что касается вашего вопроса. Теоретически производительность CTE и подзапросов должна быть одинаковой, поскольку оба предоставляют одинаковую информацию оптимизатору запросов. Одно из отличий состоит в том, что CTE, использованный более одного раза, может быть легко идентифицирован и рассчитан один раз. Результаты могут быть сохранены и прочитаны несколько раз. К сожалению, SQL Server, похоже, не использует преимущества этого базового метода оптимизации (вы можете назвать это общим устранением подзапроса).
Временные таблицы - это другое дело, потому что вы предоставляете больше рекомендаций о том, как должен выполняться запрос. Одно из основных отличий заключается в том, что оптимизатор может использовать статистику из временной таблицы для составления плана запроса. Это может привести к повышению производительности. Кроме того, если у вас есть сложный CTE (подзапрос), который используется более одного раза, то сохранение его во временной таблице часто дает повышение производительности. Запрос выполняется только один раз.
Ответ на ваш вопрос заключается в том, что вам нужно поиграть, чтобы получить ожидаемую производительность, особенно для сложных запросов, которые выполняются на регулярной основе. В идеальном мире оптимизатор запросов нашел бы идеальный путь выполнения. Хотя это часто бывает, вы можете найти способ повысить производительность.
источник
Там нет правила. Я нахожу CTE более читабельными и использую их, если только они не демонстрируют проблемы с производительностью, и в этом случае я исследую реальную проблему, а не догадываюсь, что CTE является проблемой, и пытаюсь переписать ее, используя другой подход. Обычно проблема заключается не только в том, как я решил декларативно изложить свои намерения с помощью запроса.
Конечно, есть случаи, когда вы можете распутать CTE или удалить подзапросы и заменить их таблицей #temp и сократить продолжительность. Это может быть связано с различными вещами, такими как устаревшая статистика, невозможность даже получить точную статистику (например, присоединение к табличной функции), параллелизм или даже неспособность сгенерировать оптимальный план из-за сложности запроса ( в этом случае его разбиение может дать оптимизатору шанс на победу). Но есть также случаи, когда ввод / вывод, связанный с созданием таблицы #temp, может перевесить другие аспекты производительности, которые могут сделать конкретную форму плана с использованием CTE менее привлекательной.
Честно говоря, существует слишком много переменных, чтобы дать «правильный» ответ на ваш вопрос. Не существует предсказуемого способа узнать, когда запрос может дать предпочтение тому или иному подходу - просто знайте, что теоретически одна и та же семантика для CTE или отдельного подзапроса должна выполняться точно так же. Я думаю, что ваш вопрос будет более ценным, если вы представите некоторые случаи, когда это не так - возможно, вы обнаружили ограничение в оптимизаторе (или обнаружили известный), или что ваши запросы не являются семантически эквивалентными или этот содержит элемент, который мешает оптимизации.
Поэтому я бы предложил написать запрос так, чтобы он казался вам наиболее естественным и отклонялся бы только тогда, когда вы обнаружите реальную проблему производительности, с которой сталкивается оптимизатор. Лично я оцениваю их как CTE, а затем подзапрос, где таблица #temp является последним средством.
источник
link / edit / close / flag
- если были какие-либо голоса, чтобы закрыть вопрос, вы увидите,close (n)
гдеn
указано количество пользователей, которые проголосовали за закрытие вашего вопроса. Если вы нажмете на ссылку, вы увидите причины, выбранные этими пользователями.#tetemateralized, а CTE - нет.
CTE - это просто синтаксис, поэтому в теории это просто подзапрос. Выполнено # Темп материализуется. Поэтому дорогой CTE в соединении, которое выполняется многократно, может быть лучше в #temp. С другой стороны, если это простая оценка, которая не выполняется, но несколько раз, то она не стоит накладных расходов на #temp.
Некоторые люди на SO не любят табличные переменные, но они мне нравятся, так как они материализованы и быстрее создаются, чем #temp. Есть моменты, когда оптимизатор запросов работает лучше с #temp по сравнению с табличной переменной.
Возможность создания PK для переменной #temp или таблицы дает оптимизатору запросов больше информации, чем CTE (поскольку вы не можете объявить PK в CTE).
источник
Вот две вещи, которые, я думаю, делают ВСЕГДА предпочтительным использование таблицы # Temp, а не CTE:
Вы не можете поместить первичный ключ в CTE, поэтому данные, к которым обращается CTE, должны будут проходить по каждому из индексов в таблицах CTE, а не просто обращаться к PK или Index в таблице временных данных.
Поскольку вы не можете добавлять ограничения, индексы и первичные ключи в CTE, они более подвержены ошибкам и плохим данным.
в понедельник, когда вчера
Вот пример, где ограничения #table могут предотвратить плохие данные, что не имеет место в CTE
источник
ALWAYS
слишком далеко, но спасибо за ответ. С точки зрения читабельности использование CTE может быть хорошей вещью.CHECK
ограничение, ссылающееся на несколько строк / таблиц, не допускается). Можете ли вы опубликовать пример, в котором CTE обнаруживает ошибку, которой нет в таблице временных эквивалентов?