Имеет ли значение порядок таблиц, указанных в предложении ON, в JOIN? - PullRequest
35 голосов
/ 24 апреля 2009

Имеет ли значение, каким образом я заказываю критерии в предложении ON для JOIN?

select a.Name, b.Status from a
inner join b
on a.StatusID = b.ID

против

select a.Name, b.Status from a
inner join b
on b.ID = a.StatusID

Есть ли какое-либо влияние на производительность? Что если бы у меня было несколько критериев?

Один заказ более ремонтопригоден, чем другой?

Ответы [ 9 ]

32 голосов
/ 24 апреля 2009

JOIN порядок может быть принудительно установлен путем размещения таблиц в правильном порядке в предложении FROM:

  1. В MySQL есть специальное предложение под названием STRAIGHT_JOIN, которое определяет порядок.

    Это будет использовать индекс для b.id:

    SELECT  a.Name, b.Status
    FROM    a
    STRAIGHT_JOIN
            b
    ON      b.ID = a.StatusID
    

    И это будет использовать индекс для a.StatusID:

    SELECT  a.Name, b.Status
    FROM    b
    STRAIGHT_JOIN
            a
    ON      b.ID = a.StatusID
    
  2. У Oracle есть особая подсказка ORDERED для принудительного исполнения заказа JOIN:

    Это будет использовать индекс для b.id или строить хеш-таблицу для b:

    SELECT  /*+ ORDERED */
            *
    FROM    a
    JOIN    b
    ON      b.ID = a.StatusID
    

    И это будет использовать индекс на a.StatusID или строить хеш-таблицу на a:

    SELECT  /*+ ORDERED */
            *
    FROM    b
    JOIN    a
    ON      b.ID = a.StatusID
    
  3. SQL Server имеет подсказку FORCE ORDER, которая делает то же самое:

    Это будет использовать индекс на b.id или строить хеш-таблицу на b:

    SELECT  *
    FROM    a
    JOIN    b
    ON      b.ID = a.StatusID
    OPTION (FORCE ORDER)
    

    И это будет использовать индекс на a.StatusID или строить хеш-таблицу на a:

    SELECT  *
    FROM    b
    JOIN    a
    ON      b.ID = a.StatusID
    OPTION (FORCE ORDER)
    
  4. Ребята из PostgreSQL, извините. Ваш список TODO говорит:

    Подсказки оптимизатора (не нужны)

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

Что касается порядка в сравнении, то это не имеет значения ни в одном RDBMS, AFAIK.

Хотя я лично всегда стараюсь оценить, какой столбец будет искать, и помещаю этот столбец слева (чтобы он выглядел как lvalue).

Подробнее см. этот ответ .

9 голосов
/ 24 апреля 2009

Нет, это не так.

То, что я делаю (для удобства чтения), ваш второй пример.

5 голосов
/ 24 апреля 2009

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

1 голос
/ 24 марта 2014

Как уже говорили многие: заказ не влияет на результат или производительность.

Я хочу отметить, что LINQ to SQL допускает только первый случай !

Например, следующий пример работает хорошо ...

var result = from a in db.a
             join b in db.b on a.StatusID equals b.ID
             select new { Name = a.Name, Status = b.Status }

... в то время как это приведет к ошибкам в Visual Studio:

var result = from a in db.a
             join b in db.b on b.ID equals a.StatusID
             select new { Name = a.Name, Status = b.Status }

Что выдает эти ошибки компилятора:

  • CS1937 : имя «имя» не находится в области видимости слева от слова «равно». Подумайте о том, чтобы поменять выражения по обе стороны от «равно».
  • CS1938 : имя «имя» не находится в области справа от слова «равно». Подумайте о том, чтобы поменять выражения по обе стороны от «равно».

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

1 голос
/ 24 апреля 2009

Единственная причина, по которой я не буду использовать ваш второй пример:

select a.Name, b.Status 
from a
inner join b
  on b.ID = a.StatusID

Ваш пользователь, скорее всего, вернется и скажет: «Могу ли я увидеть все a.name, даже если у них нет записей статуса?» а не «Могу ли я увидеть все b.status, даже если у них нет записи имени?», поэтому, чтобы заранее спланировать этот пример, я бы использовал On a.StatusID = b.ID в ожидании LEFT Outer Join. Это предполагает, что у вас может быть таблица «a» без «b».

Исправление: результат не изменится.

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

1 голос
/ 24 апреля 2009

Читать это

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

Если у вас есть несколько критериев, вещи обычно лениво оцениваются (но мне нужно немного изучить крайние случаи, если таковые имеются).

Для удобства чтения я обычно предпочитаю

SELECT Name, Status FROM a 
JOIN b 
ON a.StatusID = b.ID

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

1 голос
/ 24 апреля 2009

нет там нет. В конце концов, вы на самом деле просто оцениваете, является ли a = b.

А в качестве симметричного свойства равенства говорится:

  • Для любых величин a и b, если a = b, то b = a.

, поэтому, проверяете ли вы (12)*=12 или 12=(12)*, логически не имеет значения.

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

0 голосов
/ 30 марта 2018

ОШИБКА: предложение ON ссылается на таблицы справа (php sqlite 3.2)

Заменить

LEFT JOIN itm08 i8 ON  i8.id= **cdd01.idcmdds** and i8.itm like '%ormit%'  

LEFT JOIN **comodidades cdd01** ON cdd01.id_registro = u.id_registro 

Для этого

LEFT JOIN **comodidades cdd01** ON cdd01.id_registro = u.id_registro

LEFT JOIN itm08 i8 ON  i8.id= **cdd01.idcmdds** and i8.itm like '%ormit%'
0 голосов
/ 25 апреля 2009

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

select a.*, b.*
from tableA a
     inner join tableB b
          on a.name=b.name
               and a.type=b.type

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

еще одна вещь, которую я хотел бы сделать, - сделать так, чтобы мои критерии в моих инструкциях on соответствовали порядку таблицы так что если сначала а, а затем b, то слева будет a, а справа b.

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