Присоединение к подзапросу

Я старый пользователь MySQL и всегда предпочитал JOIN а не подзапрос. Но в настоящее время каждый использует подзапрос, и я ненавижу его; Я не знаю почему.

Мне не хватает теоретических знаний, чтобы судить самому, есть ли разница. Является ли подзапрос таким же хорошим, как JOIN и поэтому не о чем беспокоиться?

Ответ 1

Взято из руководства MySQL (13.2.10.11 Перезапись подзапросов как объединений):

LEFT [OUTER] JOIN может быть быстрее, чем эквивалентный подзапрос, потому что сервер может быть в состоянии оптимизировать его лучше - факт, который не относится только к MySQL Server.

Таким образом, подзапросы могут быть медленнее, чем LEFT [OUTER] JOIN, но, на мой взгляд, их сила немного выше читаемости.

Ответ 2

Подзапросы - это логически правильный способ решения проблем формы: "Получить факты из A, обусловленные фактами из B". В таких случаях логически логично вставлять B в подзапрос, чем делать соединение. Это также безопасно, в практическом смысле, поскольку вам не нужно быть осторожным в получении дублированных фактов из A из-за нескольких матчей против B.

Практически, однако, ответ обычно сводится к производительности. Некоторые оптимизаторы высасывают лимоны, когда им дается соединение по сравнению с подзапросом, а некоторые - лимоны в другом случае, и это специфичные для оптимизатора, специфичные для СУБД и специфичные для запросов.

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

Ответ 3

В большинстве случаев JOIN быстрее, чем подзапросы, и очень редко бывает, что подзапрос будет быстрее.

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

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

Ответ 4

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

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

Ответ 5

Прежде всего, чтобы сравнить два первых, вы должны различать запросы с подзапросами:

  • класс подзапросов, которые всегда имеют соответствующий эквивалентный запрос, написанный с помощью соединений
  • класс подзапросов, которые нельзя переписать с помощью объединений

Для первого класса запросов хорошая RDBMS увидит соединения и подзапросы как эквивалентные и создаст те же планы запросов.

В наши дни даже mysql делает это.

Тем не менее, иногда это не так, но это не означает, что объединения всегда будут выигрывать - у меня были случаи, когда подзапросы в mysql улучшали производительность. (Например, если есть что-то, что предотвращает планировщик mysql, чтобы правильно оценить стоимость, и если планировщик не видит вариант соединения и вариант подзапроса, как и тогда, то подзапросы могут превзойти объединения, заставив определенный путь).

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

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

Ответ 6

В 2010 году я присоединился бы к автору этого вопроса и решительно проголосовал бы за JOIN. Но с гораздо большим опытом (особенно в MySQL) я могу сказать: да, подзапросы могут быть лучше. Я прочитал несколько ответов здесь. Некоторые заявили, что подзапросы выполняются быстрее, но им не хватает хорошего объяснения. Я надеюсь, что смогу дать один (очень) поздний ответ:

Прежде всего, позвольте мне сказать самое важное: существуют различные формы подзапросов

И второе важное утверждение: размер имеет значение

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

Подзапросы в полях выбора

SELECT moo, (SELECT roger FROM wilco WHERE moo = me) AS bar FROM foo

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

Подзапросы в выражении Where

SELECT moo FROM foo WHERE bar = (SELECT roger FROM wilco WHERE moo = me)

Если вам повезет, БД оптимизирует это внутренне в JOIN. Если нет, ваш запрос станет очень, очень медленным для огромных наборов данных, потому что он будет выполнять подзапрос для каждой строки в foo, а не только для результатов, как в типе select.

Подзапросы в сообщении Join

SELECT moo, bar 
  FROM foo 
    LEFT JOIN (
      SELECT MIN(bar), me FROM wilco GROUP BY me
    ) ON moo = me

Это интересно. Мы объединяем JOIN с подзапросом. И здесь мы получаем реальную силу подзапросов. Вообразите набор данных с миллионами строк в wilco но только несколько отличают me. Вместо того, чтобы объединяться с огромным столом, теперь у нас есть меньшая временная таблица, с которой можно соединиться. Это может привести к гораздо более быстрым запросам, в зависимости от размера базы данных. Вы можете получить тот же эффект с CREATE TEMPORARY TABLE... и INSERT INTO... SELECT..., которые могут обеспечить лучшую читаемость в очень сложных запросах (но могут блокировать наборы данных на повторяющемся уровне изоляции чтения).

Вложенные подзапросы

SELECT moo, bar
  FROM (
    SELECT moo, CONCAT(roger, wilco) AS bar
      FROM foo
      GROUP BY moo
      HAVING bar LIKE 'SpaceQ%'
  ) AS temp_foo
  GROUP BY bar
  ORDER BY bar

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

Заключение

Подзапросы не являются заменой для JOIN и вы не должны использовать их таким образом (хотя это возможно). По моему скромному мнению, правильное использование подзапроса - это использование в качестве быстрой замены CREATE TEMPORARY TABLE... Хороший подзапрос сокращает набор данных таким способом, которого вы не можете выполнить в операторе ON для JOIN. Если подзапрос имеет одно из ключевых слов GROUP BY или DISTINCT и предпочтительно не находится в полях выбора или операторе where, то это может значительно повысить производительность.

Ответ 7

Документация MSDN для SQL Server говорит

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

поэтому, если вам нужно что-то вроде

select * from t1 where exists select * from t2 where t2.parent=t1.id

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

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

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

Ответ 8

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

(хотя Марсело Канто упоминает об этом)

Я приведу пример из курсов Stanford Lagunita по SQL.

Таблица студентов

+------+--------+------+--------+
| sID  | sName  | GPA  | sizeHS |
+------+--------+------+--------+
|  123 | Amy    |  3.9 |   1000 |
|  234 | Bob    |  3.6 |   1500 |
|  345 | Craig  |  3.5 |    500 |
|  456 | Doris  |  3.9 |   1000 |
|  567 | Edward |  2.9 |   2000 |
|  678 | Fay    |  3.8 |    200 |
|  789 | Gary   |  3.4 |    800 |
|  987 | Helen  |  3.7 |    800 |
|  876 | Irene  |  3.9 |    400 |
|  765 | Jay    |  2.9 |   1500 |
|  654 | Amy    |  3.9 |   1000 |
|  543 | Craig  |  3.4 |   2000 |
+------+--------+------+--------+

Применить таблицу

(заявки, сделанные в определенные университеты и майоры)

+------+----------+----------------+----------+
| sID  | cName    | major          | decision |
+------+----------+----------------+----------+
|  123 | Stanford | CS             | Y        |
|  123 | Stanford | EE             | N        |
|  123 | Berkeley | CS             | Y        |
|  123 | Cornell  | EE             | Y        |
|  234 | Berkeley | biology        | N        |
|  345 | MIT      | bioengineering | Y        |
|  345 | Cornell  | bioengineering | N        |
|  345 | Cornell  | CS             | Y        |
|  345 | Cornell  | EE             | N        |
|  678 | Stanford | history        | Y        |
|  987 | Stanford | CS             | Y        |
|  987 | Berkeley | CS             | Y        |
|  876 | Stanford | CS             | N        |
|  876 | MIT      | biology        | Y        |
|  876 | MIT      | marine biology | N        |
|  765 | Stanford | history        | Y        |
|  765 | Cornell  | history        | N        |
|  765 | Cornell  | psychology     | Y        |
|  543 | MIT      | CS             | N        |
+------+----------+----------------+----------+

Попробуйте найти оценки GPA для студентов, которые применили к CS major (независимо от университета)

Использование подзапроса:

select GPA from Student where sID in (select sID from Apply where major = 'CS');

+------+
| GPA  |
+------+
|  3.9 |
|  3.5 |
|  3.7 |
|  3.9 |
|  3.4 |
+------+

Среднее значение для этого набора результатов:

select avg(GPA) from Student where sID in (select sID from Apply where major = 'CS');

+--------------------+
| avg(GPA)           |
+--------------------+
| 3.6800000000000006 |
+--------------------+

Использование соединения:

select GPA from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';

+------+
| GPA  |
+------+
|  3.9 |
|  3.9 |
|  3.5 |
|  3.7 |
|  3.7 |
|  3.9 |
|  3.4 |
+------+

среднее значение для этого набора результатов:

select avg(GPA) from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';

+-------------------+
| avg(GPA)          |
+-------------------+
| 3.714285714285714 |
+-------------------+

Очевидно, что вторая попытка дает вводящие в заблуждение результаты в нашем случае использования, учитывая, что она подсчитывает дубликаты для вычисления среднего значения. Также очевидно, что использование distinct с утверждением на основе соединения будет не устранять проблему, учитывая, что она ошибочно сохранит одно из трех вхождений показателя 3.9. Правильный случай состоит в том, чтобы учитывать TWO (2) вхождения баллов 3.9, учитывая, что у нас на самом деле есть TWO (2) студенты с таким результатом, которые соответствуют нашему запросу критерии.

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

Ответ 9

Запуск в очень большой базе данных из старой Mambo CMS:

SELECT id, alias
FROM
  mos_categories
WHERE
  id IN (
    SELECT
      DISTINCT catid
    FROM mos_content
  );

0 секунд

SELECT
  DISTINCT mos_content.catid,
  mos_categories.alias
FROM
  mos_content, mos_categories
WHERE
  mos_content.catid = mos_categories.id;

~ 3 секунды

EXPLAIN показывает, что они просматривают то же самое количество строк, но один занимает 3 секунды, а один близок к мгновенному. Мораль истории? Если производительность важна (когда это не так?), Попробуйте несколько способов и посмотрите, какая из них самая быстрая.

А...

SELECT
  DISTINCT mos_categories.id,
  mos_categories.alias
FROM
  mos_content, mos_categories
WHERE
  mos_content.catid = mos_categories.id;

0 секунд

Опять же, те же результаты, одинаковое количество строк. Я предполагаю, что DISTINCT mos_content.catid занимает гораздо больше времени, чем выяснение, чем DISTINCT mos_categories.id делает.

Ответ 10

Подзапросы обычно используются для возврата одной строки в качестве атомного значения, хотя они могут использоваться для сравнения значений с несколькими строками с ключевым словом IN. Они разрешены практически в любой значимой точке SQL-запроса, включая целевой список, предложение WHERE и т.д. В качестве условия поиска можно использовать простой подзапрос. Например, между парой таблиц:

   SELECT title FROM books WHERE author_id = (SELECT id FROM authors WHERE last_name = 'Bar' AND first_name = 'Foo');

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

   SELECT title FROM books WHERE author_id IN (SELECT id FROM authors WHERE last_name ~ '^[A-E]');

Это, очевидно, отличается от LEFT-JOIN, где вы просто хотите присоединиться к материалам из таблиц A и B, даже если условие соединения не находит подходящей записи в таблице B и т.д.

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

Ответ 11

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

Но в случае, если в таблице содержится более 100 000 записей, лучшим результатом будет подзапрос.

У меня есть одна таблица, в которой 500 000 записей, которые я создал ниже запроса, и время его результата, как

SELECT * 
FROM crv.workorder_details wd 
inner join  crv.workorder wr on wr.workorder_id = wd.workorder_id;

Результат: 13,3 секунды

select * 
from crv.workorder_details 
where workorder_id in (select workorder_id from crv.workorder)

Результат: 1,65 секунды

Ответ 12

Версия MySQL: 5.5.28-0ubuntu0.12.04.2-log

У меня также сложилось впечатление, что JOIN всегда лучше, чем подзапрос в MySQL, но EXPLAIN - лучший способ сделать суждение. Вот пример, где sub-запросы работают лучше, чем JOINs.

Вот мой запрос с тремя подзапросами:

EXPLAIN SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date 
FROM `vote-ranked-listory` vrl 
INNER JOIN lists l ON l.list_id = vrl.list_id 
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION' 
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5 
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000 
 AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=43) IS NULL 
 AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=55) IS NULL 
 AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL 
ORDER BY vrl.moved_date DESC LIMIT 200;

EXPLAIN показывает:

+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| id | select_type        | table    | type   | possible_keys                                       | key          | key_len | ref                                             | rows | Extra                    |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
|  1 | PRIMARY            | vrl      | index  | PRIMARY                                             | moved_date   | 8       | NULL                                            |  200 | Using where              |
|  1 | PRIMARY            | l        | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY      | 4       | ranker.vrl.list_id                              |    1 | Using where              |
|  1 | PRIMARY            | vrlih    | eq_ref | PRIMARY                                             | PRIMARY      | 9       | ranker.vrl.list_id,ranker.vrl.ontology_id,const |    1 | Using where              |
|  1 | PRIMARY            | lbs      | eq_ref | PRIMARY,idx_list_burial_state,burial_score          | PRIMARY      | 4       | ranker.vrl.list_id                              |    1 | Using where              |
|  4 | DEPENDENT SUBQUERY | list_tag | ref    | list_tag_key,list_id,tag_id                         | list_tag_key | 9       | ranker.l.list_id,const                          |    1 | Using where; Using index |
|  3 | DEPENDENT SUBQUERY | list_tag | ref    | list_tag_key,list_id,tag_id                         | list_tag_key | 9       | ranker.l.list_id,const                          |    1 | Using where; Using index |
|  2 | DEPENDENT SUBQUERY | list_tag | ref    | list_tag_key,list_id,tag_id                         | list_tag_key | 9       | ranker.l.list_id,const                          |    1 | Using where; Using index |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+

Тот же запрос с JOINs:

EXPLAIN SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date 
FROM `vote-ranked-listory` vrl 
INNER JOIN lists l ON l.list_id = vrl.list_id 
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION' 
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5 
LEFT JOIN list_tag lt1 ON lt1.list_id = vrl.list_id AND lt1.tag_id = 43 
LEFT JOIN list_tag lt2 ON lt2.list_id = vrl.list_id AND lt2.tag_id = 55 
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403 
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000 
AND lt1.list_id IS NULL AND lt2.tag_id IS NULL 
ORDER BY vrl.moved_date DESC LIMIT 200;

а выход:

+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type   | possible_keys                                       | key          | key_len | ref                                         | rows | Extra                                        |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | lt3   | ref    | list_tag_key,list_id,tag_id                         | tag_id       | 5       | const                                       | 2386 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | l     | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY      | 4       | ranker.lt3.list_id                          |    1 | Using where                                  |
|  1 | SIMPLE      | vrlih | ref    | PRIMARY                                             | PRIMARY      | 4       | ranker.lt3.list_id                          |  103 | Using where                                  |
|  1 | SIMPLE      | vrl   | ref    | PRIMARY                                             | PRIMARY      | 8       | ranker.lt3.list_id,ranker.vrlih.ontology_id |   65 | Using where                                  |
|  1 | SIMPLE      | lt1   | ref    | list_tag_key,list_id,tag_id                         | list_tag_key | 9       | ranker.lt3.list_id,const                    |    1 | Using where; Using index; Not exists         |
|  1 | SIMPLE      | lbs   | eq_ref | PRIMARY,idx_list_burial_state,burial_score          | PRIMARY      | 4       | ranker.vrl.list_id                          |    1 | Using where                                  |
|  1 | SIMPLE      | lt2   | ref    | list_tag_key,list_id,tag_id                         | list_tag_key | 9       | ranker.lt3.list_id,const                    |    1 | Using where; Using index                     |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+

Сравнение столбца rows указывает разницу, и запрос с JOINs использует Using temporary; Using filesort.

Конечно, когда я запускаю оба запроса, первый выполняется через 0,02 секунды, второй не завершается даже через 1 минуту, поэтому EXPLAIN правильно объяснил эти запросы.

Если у меня нет INNER JOIN в таблице list_tag, если я удалю

AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL  

из первого запроса и соответственно:

INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403

из второго запроса, тогда EXPLAIN возвращает одинаковое количество строк для обоих запросов, и оба этих запроса выполняются одинаково быстро.

Ответ 13

Подзапросы имеют возможность вычислять функции агрегации на лету. Например. Найдите минимальную цену книги и получите все книги, которые продаются с этой ценой. 1) Использование подзапросов:

SELECT titles, price
FROM Books, Orders
WHERE price = 
(SELECT MIN(price)
 FROM Orders) AND (Books.ID=Orders.ID);

2), используя JOINs

SELECT MIN(price)
     FROM Orders;
-----------------
2.99

SELECT titles, price
FROM Books b
INNER JOIN  Orders o
ON b.ID = o.ID
WHERE o.price = 2.99;

Ответ 14

  • Общее правило заключается в том, что в большинстве случаев объединения выполняются быстрее (99%).
  • Чем больше таблиц данных, тем медленнее подзапросы.
  • Чем меньше таблиц данных, тем меньше у подзапросов скорость соединения.
  • Подзапросы проще, легче для понимания и легче для чтения.
  • Большинство веб-фреймворков и фреймворков приложений, а также их ORM и Active record генерируют запросы с подзапросами, потому что с подзапросами легче разделить ответственность, поддерживать код и т.д.
  • Для небольших веб-сайтов или приложений подзапросы - это нормально, но для больших веб-сайтов и приложений вам часто приходится переписывать сгенерированные запросы, чтобы объединить запросы, особенно если запрос использует много подзапросов в запросе.

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

Ответ 15

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

SELECT ProductID,
       Name,
       ListPrice,
       (SELECT AVG(ListPrice)
        FROM Production.Product
       ) AS AvgListPrice
FROM Production.Product
WHERE ListPrice > (SELECT AVG(ListPrice)
                   FROM Production.Product
                  )

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

SELECT Product.Name,
       ProductModel.Name AS ModelName
FROM Production.product
INNER JOIN Production.ProductModel
ON Product.ProductModelID = ProductModel.ProductModelID

В этом заявлении использовалась INNER JOIN для сопоставления строк из таблиц Product и ProductModel. Обратите внимание, что столбец ProducModel.Name доступен для использования во всем запросе. Объединенный набор строк затем доступен оператором select для использования для отображения, фильтрации или группировки по столбцам. Это отличается от подзапроса. Там подзапрос возвращает результат, который сразу используется. Обратите внимание, что он является неотъемлемой частью оператора select. Он не может стоять сам по себе, поскольку подзапрос может.

Ответ 16

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

У нас была таблица пользователей из ста тысяч записей и их данных о членстве (дружбе) около 3сот тысяч записей. Это было выражение о присоединении, чтобы забрать друзей и их данные, но с большой задержкой. Но он отлично работал, когда в таблице членства был только небольшой объем данных. Как только мы изменили его, чтобы использовать подзапрос, он работал нормально.

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

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

Ответ 17

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

Ответ 18

Я просто думаю о той же проблеме, но я использую подзапрос в части FROM. Мне нужно подключиться и запросить из больших таблиц, в "ведомой" таблице содержится 28 миллионов записей, но результат всего 128, так что малый результат - большие данные! Я использую функцию MAX() на нем.

Сначала я использую LEFT JOIN, потому что я думаю, что это правильный путь, mysql может оптимизировать и т.д.

Время выполнения левого соединения: 1.12 с Время выполнения SUB-SELECT: 0.06 с

В 18 раз быстрее выбор, чем объединение! Просто в ад Чокито. Подвыбор выглядит ужасно, но результат...

Ответ 19

Если вы хотите ускорить ваш запрос с помощью соединения:

Для "внутреннего соединения/соединения" не используйте условие "вместо", вместо этого используйте его в состоянии "ВКЛ". Например:

     select id,name from table1 a  
   join table2 b on a.name=b.name
   where id='123'

 Try,

    select id,name from table1 a  
   join table2 b on a.name=b.name and a.id='123'

Для "левого/правого соединения", не используйте в состоянии "ON", потому что, если вы используете левое/правое соединение, оно получит все строки для любой таблицы. Так что, не используйте его в "On". Итак, попробуйте использовать условие "Где"