SQL: запрос подобен этому, или есть более эффективный способ сделать это, например, использовать соединение? - PullRequest
5 голосов
/ 22 января 2010

Мне часто хочется написать SQL-запрос, подобный следующему:

SELECT body 
  FROM node_revisions 
 where vid = (SELECT vid 
                FROM node 
               WHERE nid = 4);

Я знаю, что есть соединения и вещи, которые вы могли бы сделать, но они, кажется, усложняют ситуацию Объединения - лучший способ сделать это? Это более эффективно? Проще понять?

Ответы [ 8 ]

7 голосов
/ 22 января 2010

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

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

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

Вот как будет выглядеть соединение:

SELECT body 
FROM node_revisions nr
INNER JOIN node n
  ON nr.vid = n.vid
WHERE n.nid = 4

Я бы не стал использовать отправленный вами запрос, поскольку существует вероятность более чем одной записи узла с nid = 4, что может привести к его отказу.

Я бы использовал:

SELECT body 
FROM node_revisions 
WHERE vid IN (SELECT vid 
             FROM node 
             WHERE nid = 4);

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

3 голосов
/ 22 января 2010

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

SELECT body 
  FROM node_revisions 
    inner join node 
      on (node_revisions.vid = node.vid)
  WHERE node.nid = 4
3 голосов
/ 22 января 2010

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

Объединения лучше и проще для понимания

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

Письменные запросы не имеют ничего общего с эффективностью *

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

(* Можно написать ужасный запрос, который неэффективен, но для этого требуется особый вид сумасшествия.)

select
  body

from node_revisions nr

join node n
on n.vid = nr.vid

where n.nid = 4
2 голосов
/ 23 января 2010

Объединение интересно:

select body 
from node_revisions nr
join node n on nr.vid = n.vid
where n.vid = 4

Но вы также можете выразить объединение без объединения [!]:

select body 
from node_revisions nr, node n
where n.nid = 4 and nr.vid = n.vid

Интересно, что SQL Server предоставляет несколько разные планы запросов для обоих запросов, в то время как объединение имеет сканирование кластеризованного индекса, вместо «объединения без объединения» вместо поиска кластеризованного индекса, что указывает на лучше , по крайней мере, в этом случае!

1 голос
/ 22 января 2010
SELECT  body 
FROM    node_revisions 
WHERE   vid =
        (
        SELECT  vid 
        FROM    node 
        WHERE   nid = 4
        )

Этот запрос логически эквивалентен объединению, если и только если nid является PRIMARY KEY или охватывается ограничением UNIQUE.

В противном случае запросы не эквивалентны: объединение всегда будет успешным, в то время как подзапрос завершится ошибкой, если в node есть строка более чем 1 с nid = 4.

Если nid является PRIMARY KEY, тогда JOIN и подзапрос будут иметь одинаковую производительность.

В случае объединения node станет ведущим

В случае подзапроса подзапрос будет выполнен один раз и преобразован в const на этапе разбора.

1 голос
/ 22 января 2010

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

1 голос
/ 22 января 2010

Последний код MySQL 6.x автоматически преобразует это выражение IN в INNER JOIN с помощью оптимизации подзапроса с полусоединением , что делает 2 оператора в значительной степени эквивалентными:

http://forge.mysql.com/worklog/task.php?id=3740

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

select body from node_revisions r, node n where r.vid = n.vid and n.node = 4
1 голос
/ 22 января 2010
select 
     body 
from node_revisions A 
where exists (select 'x' 
              from Node B 
              Where A.Vid = B.Vid and B.NID=4)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...