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

Запросы JOIN быстрее, чем несколько запросов? (Вы запускаете свой основной запрос, а затем запускаете много других SELECT на основе результатов вашего основного запроса)

Я спрашиваю, потому что ПРИСОЕДИНИТЬСЯ к ним будет усложнять LOT дизайн моего приложения

Если они быстрее, может ли кто-нибудь приблизительно приблизиться к тому, сколько? Если это 1.5x, мне все равно, но если это 10x, я думаю, что да.

Ответ 1

Это слишком неопределенно, чтобы дать вам ответ, относящийся к вашему конкретному делу. Это зависит от многих вещей. Джефф Этвуд (основатель этого сайта) на самом деле написал об этом. По большей части, хотя, если у вас есть правильные индексы, и вы правильно делаете свои JOINs, обычно будет быстрее совершить 1 поездку, чем несколько.

Ответ 2

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

  • Одиночный запрос с 5 соединениями

    запрос: 8.074508 секунд

    размер результата: 2268000

  • 5 запросов в строке

    комбинированное время запроса: 0.00262 секунды

    размер результата: 165 (6 + 50 + 7 + 12 + 90)

.

Заметим, что мы получаем те же результаты в обоих случаях (6 x 50 x 7 x 12 x 90 = 2268000)

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

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

В качестве примечания, мой сервер MySQL находится рядом с моим сервером приложений... поэтому время соединения незначительно. Если ваше время соединения в секундах, возможно, есть преимущество

Франк

Ответ 3

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

Я могу понять, если один из способов запроса занимает 0,02 секунды, а другой занимает 20 секунд, это огромная разница. Но что, если один из способов запроса занимает 0,0000000002 секунды, а другой занимает 0,0000002 секунды? В обоих случаях один путь - это колоссальный 1000 раз быстрее, чем другой, но действительно ли он действительно все еще "whopping" во втором случае?

Нижняя строка, как я лично вижу: если она работает хорошо, идите для легкого решения.

Ответ 4

Был ли быстрый тест, выбрав одну строку из таблицы из 50 000 строк и соединившись с одной строкой из таблицы из 100 000 строк. В основном выглядели:

$id = mt_rand(1, 50000);
$row = $db->fetchOne("SELECT * FROM table1 WHERE id = " . $id);
$row = $db->fetchOne("SELECT * FROM table2 WHERE other_id = " . $row['other_id']);

против

$id = mt_rand(1, 50000);
$db->fetchOne("SELECT table1.*, table2.*
    FROM table1
    LEFT JOIN table1.other_id = table2.other_id
    WHERE table1.id = " . $id);

Два метода select заняли 3,7 секунды для 50 000 просмотров, тогда как JOIN занял 2,0 секунды на моем домашнем медленном компьютере. INNER JOIN и LEFT JOIN не повлияли. Получение нескольких строк (например, с помощью IN SET) дало аналогичные результаты.

Ответ 5

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

Тогда еще лучше - добавьте "EXPLAIN" в начало каждого запроса. Это покажет вам, сколько подзапросов MySQL использует для ответа на ваш запрос на данные и сколько строк проверено для каждого запроса.

Ответ 6

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

Попробуйте запустить статистику базы данных как для JOIN, так и для нескольких SELECT. Смотрите, если в вашей среде JOIN работает быстрее/медленнее, чем SELECT.

И снова, если изменить его на JOIN будет означать дополнительный день/неделю/месяц работы dev, я бы придерживался нескольких SELECT

Приветствия,

BLT

Ответ 7

Реальный вопрос: есть ли у этих записей отношение один-к-одному или отношение один-ко-многим?

Ответ TL;DR:

Если один к одному, используйте оператор JOIN.

Если один ко многим, используйте одну (или несколько) SELECT с оптимизацией кода на стороне сервера.

Почему и как использовать SELECT для оптимизации

SELECT (с несколькими запросами вместо объединений) для большой группы записей на основе отношения "один ко многим" обеспечивает оптимальную эффективность, так как у JOIN возникает проблема экспоненциальной утечки памяти. Соберите все данные, а затем используйте язык сценариев на стороне сервера, чтобы разобраться в них:

SELECT * FROM Address WHERE Personid IN(1,2,3);

Результаты:

Address.id : 1            // First person and their address
Address.Personid : 1
Address.City : "Boston"

Address.id : 2            // First person second address
Address.Personid : 1
Address.City : "New York"

Address.id : 3            // Second person address
Address.Personid : 2
Address.City : "Barcelona"

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

<?php
    foreach($addresses as $address) {
         $persons[$address['Personid']]->Address[] = $address;
    }
?>

Когда не использовать JOIN для оптимизации

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

Но JOIN неэффективен при получении записей с отношением один ко многим.

Пример: Блоги базы данных имеют 3 таблицы интереса: Blogpost, Tag и Comment.

SELECT * from BlogPost
LEFT JOIN Tag ON Tag.BlogPostid = BlogPost.id
LEFT JOIN Comment ON Comment.BlogPostid = BlogPost.id;

Если есть 1 запись блога, 2 тега и 2 комментария, вы получите следующие результаты:

Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag2, comment1,
Row4: tag2, comment2,

Обратите внимание, как дублируется каждая запись. Итак, 2 комментария и 2 тега - это 4 строки. Что если у нас есть 4 комментария и 4 тега? Вы не получаете 8 строк - вы получаете 16 строк:

Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag1, comment3,
Row4: tag1, comment4,
Row5: tag2, comment1,
Row6: tag2, comment2,
Row7: tag2, comment3,
Row8: tag2, comment4,
Row9: tag3, comment1,
Row10: tag3, comment2,
Row11: tag3, comment3,
Row12: tag3, comment4,
Row13: tag4, comment1,
Row14: tag4, comment2,
Row15: tag4, comment3,
Row16: tag4, comment4,

Добавьте больше таблиц, больше записей и т.д., И проблема быстро раздуется до сотен строк, которые в основном заполнены избыточными данными.

Сколько стоят эти дубликаты? Память (в SQL-сервере и коде, который пытается удалить дубликаты) и сетевые ресурсы (между SQL-сервером и вашим сервером кода).

Источник: https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html; https://dev.mysql.com/doc/workbench/en/wb-relationship-tools.html

Ответ 8

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

При взаимодействии с базой данных из другого приложения, например PHP, есть аргумент одной поездки на сервер по многим.

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

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

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

Ответ 9

Будет ли это быстрее с точки зрения пропускной способности? Вероятно. Но он также потенциально блокирует больше объектов базы данных за раз (в зависимости от вашей базы данных и вашей схемы) и тем самым уменьшает concurrency. По моему опыту люди часто вводят в заблуждение аргумент "меньшее количество обращений к базам данных", когда в действительности на большинстве OLTP-систем, где база данных находится в одной локальной сети, реальным узким местом редко является сеть.

Ответ 10

Вот ссылка с 100 полезными запросами, они протестированы в базе данных Oracle, но помните, что SQL является стандартом, что отличает Oracle, MS SQL Server, MySQL и другие базы данных от диалекта SQL:

http://javaforlearn.com/100-sql-queries-learn/

Ответ 11

Этот вопрос старый, но в нем отсутствуют некоторые критерии. Я сравнил JOIN с его 2 конкурентами:

  • N + 1 запросов
  • 2 запроса, второй с использованием WHERE IN(...) или эквивалентного

Результат ясен: на MySQL JOIN намного быстрее. N + 1 запросы могут резко снизить производительность приложения:

JOIN vs WHERE IN vs N+1

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

JOIN vs N+1 - all records pointing to the same foreign record

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

вынос:

  • Для отношений *-to-one всегда используйте JOIN
  • Для отношений *-ко-многим второй запрос может быть быстрее

Смотрите мою статью на Medium для получения дополнительной информации.

Ответ 12

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

Реальный вопрос: как вы хотите получить доступ к данным. Single выбирает поддержку позднего связывания. Например, если вам нужна информация о сотрудниках, вы можете выбрать ее из таблицы Сотрудники. Внешние ключевые отношения могут использоваться для извлечения связанных ресурсов в более позднее время и по мере необходимости. У выбора будет уже установлен ключ, чтобы они были очень быстрыми, и вам нужно только получить то, что вам нужно. Латентность сети всегда должна учитываться.

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

Ответ 13

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

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

Это часто вызвано отношениями "многие к одному". Например, в ответе HoldOffHunger упоминается один запрос для сообщений, тегов и комментариев. Комментарии связаны с постом, как и теги... но теги не имеют отношения к комментариям.

+------------+     +---------+     +---------+
|  comment   |     |   post  |     |  tag    |
|------------|*   1|---------|1   *|---------|
| post_id    |-----| post_id |-----| post_id |
| comment_id |     | ...     |     | tag_id  |
| user_id    |     |         |     | ...     |
| ...        |     |         |     | ...     |
+------------+     +---------+     +---------+

В этом случае однозначно лучше, чтобы это было как минимум два отдельных запроса. Если вы попытаетесь объединить теги и комментарии, поскольку между ними нет прямой связи, вы получите все возможные комбинации тегов и комментариев. many * many == manymany. Кроме того, поскольку посты и теги не связаны, вы можете выполнять эти два запроса параллельно, что приведет к потенциальной выгоде.

Давайте рассмотрим другой сценарий: вы хотите, чтобы комментарии были прикреплены к сообщению, и контактная информация комментаторов.

 +----------+     +------------+     +---------+
 |   user   |     |  comment   |     |   post  |
 |----------|1   *|------------|*   1|---------|
 | user_id  |-----| post_id    |-----| post_id |
 | username |     | user_id    |     | ...     |
 | ...      |     | ...        |     +---------+
 +----------+     +------------+

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

Ответ 14

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

Почему бы не протестировать оба сценария, тогда вы точно знаете...