LEFT JOIN против нескольких операторов SELECT - PullRequest
6 голосов
/ 18 декабря 2008

Я работаю над чужим PHP-кодом и вижу этот шаблон снова и снова:

(псевдокод)

result = SELECT blah1, blah2, foreign_key FROM foo WHERE key=bar

if foreign_key > 0  
  other_result = SELECT something FROM foo2 WHERE key=foreign_key  
end

Код должен быть разветвлен, если в другой таблице нет связанной строки, но разве это нельзя сделать лучше, выполнив LEFT JOIN в одном операторе SELECT? Я упускаю какой-то выигрыш в производительности? Проблема переносимости? Или я просто придираюсь?

Ответы [ 13 ]

6 голосов
/ 18 декабря 2008

Это определенно неправильно. Вы идете по проводу во второй раз без причины. БД очень быстры в своем проблемном пространстве. Присоединение таблиц является одним из таких способов, и вы увидите, что во втором запросе вы увидите снижение производительности по сравнению с объединением. Если в вашем табличном пространстве нет сотен миллионов записей, это не очень хорошая идея.

5 голосов
/ 18 декабря 2008

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

Для определенных комбинаций размера таблицы, конфигурации базы данных и того, как часто запрашивается внешняя таблица, выполнение этих двух запросов может быть намного быстрее, чем LEFT JOIN. Но опыт и тестирование - это единственное, что скажет вам . MySQL с умеренно большими таблицами, кажется, восприимчив к этому, IME. Выполнение трех запросов к одной таблице часто может быть намного быстрее, чем один запрос, объединяющий три. Я видел ускорения на порядок.

3 голосов
/ 18 декабря 2008

Я с тобой - лучше один SQL

2 голосов
/ 18 декабря 2008

Вы совершенно правы, что единственный запрос - это путь. Чтобы добавить некоторую ценность другим предложенным ответам, позвольте мне добавить следующую аксиому: «Используйте правильный инструмент для работы, сервер баз данных должен обрабатывать запросы, код должен обрабатывать процедурные работы».

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

2 голосов
/ 18 декабря 2008

Наиболее вероятное объяснение состоит в том, что разработчик просто не знает, как работают внешние объединения. Это очень распространено, даже среди разработчиков, которые имеют опыт работы по своей специальности.

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

Миф об избежании объединений подобен тому, что нам следует избегать написания циклов в коде нашего приложения, поскольку многократный запуск строки кода, очевидно, медленнее, чем один раз. Не говоря уже о «издержках» ++i и тестировании i<20 во время каждой итерации!

2 голосов
/ 18 декабря 2008

Мне кажется, что то, что вы говорите, вполне справедливо - зачем запускать два вызова базы данных, когда это будет сделано - если только обе записи не нужны независимо как объекты (?)

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

Это было бы лучше читать как запрос:

Select a.blah1, a.blah2, b.something From foo a Left Join foo2 b On a.foreign_key = b.key Where a.Key = bar;

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

Да, я думаю, что то, что вы говорите, правильно.

2 голосов
/ 18 декабря 2008

Существует опасность обращения к вашей СУБД SQL, как к файловой системе ISAM, выбирая ее из одной таблицы за раз. Возможно, было бы лучше использовать один SELECT с внешним соединением. С другой стороны, обнаружение нулевого значения в коде приложения и решение о том, что делать на основе нулевого или ненулевого, также не является полностью чистым.

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

В среднем, тогда один оператор SELECT лучше. Это дает оптимизатору что-то делать, а также делает его скучающим.

1 голос
/ 06 ноября 2014

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

Объединение сканирует как таблицы, так и циклы, чтобы найти первую запись таблицы во второй таблице. Простой запрос на выбор будет работать быстрее во многих случаях, так как он заботится только о первичном / уникальном ключе (если он существует) для внутреннего поиска данных.

1 голос
/ 18 декабря 2008

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

1 голос
/ 18 декабря 2008

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

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

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