В порядке ли внутренние запросы? - PullRequest
4 голосов
/ 05 июля 2011

Я часто вижу что-то вроде ...

SELECT events.id, events.begin_on, events.name
  FROM events
 WHERE events.user_id IN ( SELECT contacts.user_id 
                             FROM contacts 
                            WHERE contacts.contact_id = '1')
   OR events.user_id IN ( SELECT contacts.contact_id 
                            FROM contacts 
                           WHERE contacts.user_id = '1')

Можно ли иметь запрос в запросе?Это "внутренний запрос"?"Sub-запрос"?Это считается как три запроса (мой пример)?Если это плохо ... как я могу переписать мой пример?

Ответы [ 4 ]

3 голосов
/ 05 июля 2011

Это зависит от базы данных, особенно если сравниваемые столбцы

  • проиндексированы или нет
  • обнуляемы или нет

...,но обычно, если ваш запрос не использует столбцы из таблицы, к которой вы присоединились - вы должны использовать либо IN, либо EXISTS:

SELECT e.id, e.begin_on, e.name
  FROM EVENTS e
 WHERE EXISTS (SELECT NULL
                 FROM CONTACTS c 
                WHERE ( c.contact_id = '1' AND c.user_id = e.user_id )
                   OR ( c.user_id = '1' AND c.contact_id = e.user_id )

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

EXISTS

Хотя предложения EXISTS выглядят как коррелированные подзапросы, они не выполняются как таковые (RBAR: Row By Agonizing Row).EXISTS возвращает логическое значение на основе предоставленных критериев и завершается при первом истинном экземпляре - это может сделать его быстрее, чем IN при работе с дубликатами в дочерней таблице.

3 голосов
/ 05 июля 2011

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

Вы можете переписать свои подзапросы, используя объединения и GROUP BY, но производительность может варьироваться, особенно в зависимости отваша РСУБД.

1 голос
/ 05 июля 2011

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

В вашем примере выполняются три запроса: основной запрос SELECT и два подзапроса SELECT..

SELECT events.id, events.begin_on, events.name
FROM events
JOIN contacts
ON (events.user_id = contacts.contact_id OR events.user_id = contacts.user_id)
WHERE events.user_id = '1'
GROUP BY events.id

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

См. mysql.документы по теме.

1 голос
/ 05 июля 2011

Вы можете JOIN вместо таблицы контактов:

SELECT events.id, events.begin_on, events.name
FROM events
JOIN contacts
ON (events.user_id = contacts.contact_id OR events.user_id = contacts.user_id)
WHERE events.user_id = '1'
GROUP BY events.id  
-- exercise: without the GROUP BY, how many duplicate rows can you end up with?

Это оставляет следующий вопрос для базы данных: «Должны ли мы просмотреть всю таблицу контактов и найти все 1 в различных столбцах, или сделать что-то еще?» где ваш оригинальный SQL не давал ему большого выбора.

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