Как избежать вложенных запросов

Насколько важно избегать вложенных запросов.

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

Так они действительно так плохо. Есть ли способ использовать вложенные запросы без временных таблиц и filesort

Ответы

Ответ 1

Это действительно зависит от того, где я улучшил некоторые запросы, используя подзапросы.

Я знаю, что следующие факторы:

  • Если подзапрос использует поля из внешнего запроса для сравнения или нет (correlated или нет)
  • если отношение между внешним запросом и подзапросом покрывается индексами
  • если в соединениях нет доступных индексов, а подзапрос не коррелирован и возвращает небольшой результат, он может быстрее использовать его
  • Я также сталкиваюсь с ситуациями, в которых преобразование запроса, использующего порядок, в запрос, который его не использует, и превращение его в простой подзапрос и сортировку, что повышает производительность в mysql

В любом случае, всегда полезно тестировать различные варианты (с SQL_NO_CACHE, пожалуйста), и превращение коррелированных запросов в соединения является хорошей практикой.

Я бы даже зашел так далеко, чтобы назвать это очень полезной практикой.

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

EDIT: Процедурный и реляционный
Мышление в терминах заданных операций против процедурного сводится к эквивалентности в некоторых выражении алгебры множеств, например, выбор в союзе эквивалентен объединению выборов. Между ними нет никакой разницы.
Но когда вы сравниваете две процедуры, например, применяете критерии выбора к каждому элементу объединения с объединением, а затем применяете выбор, эти два являются совершенно разными процедурами, которые могут иметь очень разные свойства (например, использование CPU, I/O, память).

Идея реляционных баз данных заключается в том, что вы не пытаетесь описать, как получить результат (процедуру), а только то, что вы хотите, и что система управления базами данных примет решение о наилучшем пути (процедуре) для выполнения вашего запроса, Вот почему SQL называется Язык 4-го поколения (4GL).

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

Поэтому вам не нужно думать, как, только то, что.

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

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

(Примечание: выше обсуждается теоретический фон, важный для проектирования базы данных, практически все вышеперечисленные понятия отклоняются - не все эквивалентные перезаписывания запроса обязательно выполняются, так как быстрые кластеризованные первичные ключи делают таблицы наследуемым порядком на диске и т.д. но эти отклонения - это только отклонения, а тот факт, что не все эквивалентные запросы выполняются так быстро, - это несовершенство реальной СУБД, а не понятий, лежащих за ней.

Ответ 2

Я не уверен, как это выглядит в MySQL 5.1 или 5.5, но в 5.0.x вложенных запросах обычно бывает ужасная производительность, потому что MySQL выполняет подзапрос для каждой строки, полученной из основного запроса. Это, вероятно, не относится к более зрелым базам данных, таким как MsSQL, которые внутренне могут переписывать вложенные запросы в соединения, но я никогда не использовал MsSQL, поэтому я не знаю точно.

http://dev.mysql.com/doc/refman/5.0/en/rewriting-subqueries.html

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

Подзапросы против соединений

Ответ 3

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