2016-11-27 5 views
2

Я интересно, если есть способ, чтобы принести name информации user_id, sender_user_id и recipient_user_id из схемы в this fiddle.избежать многократных внутренних соединений, чтобы добавить новый столбец (информация) из тех же таблиц

Единственный способ, которым я могу думать сейчас, чтобы сделать это вложенное внутреннее соединение, которое я чувствую, как неэффективно:

SELECT e.id 
    ,msg_owner 
    ,msg_owner_name 
    ,sender_user_id 
    ,sender_name 
    ,recipient_user_id 
    ,f.NAME AS recipient_name 
    ,msg_body 
    ,created_at 
FROM (
    SELECT c.id 
     ,msg_owner 
     ,msg_owner_name 
     ,sender_user_id 
     ,d.NAME AS sender_name 
     ,recipient_user_id 
     ,msg_body 
     ,created_at 
    FROM (
     SELECT a.id 
      ,user_id AS msg_owner 
      ,NAME AS msg_owner_name 
      ,sender_user_id 
      ,recipient_user_id 
      ,msg_body 
      ,created_at 
     FROM messages AS a 
     INNER JOIN users AS b ON a.user_id = b.id 
     ) AS c 
    INNER JOIN users AS d ON c.sender_user_id = d.id 
    ) AS e 
INNER JOIN users AS f ON e.recipient_user_id = f.id 

Есть ли (более эффективный) способ привлечь name значений для каждого из вышеупомянутые три столбца? Спасибо за ваши ответы/предложения!

+1

В ваших многочисленных внутренних соединениях нет ничего плохого. Это совершенно нормально и правильно. Единственное изменение, которое я сделал бы, это то, что вам не нужны три вложенных выбора. 'SELECT a.id, b.id, c.id FROM INNER JOIN b ON aa = bx INNER JOIN c ON ab = cy' отлично работает ... – MatBailie

+1

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

+0

@MatBailie Спасибо за предложение! – user1330974

ответ

1

Просто используйте соединения, не вложенные соединения.

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

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

SELECT m.id 
    ,owner.id AS msg_owner 
    ,owner.name AS msg_owner_name 
    ,m.sender_user_id 
    ,sender.name AS sender_name 
    ,m.recipient_user_id 
    ,recipient.name AS recipient_name 
    ,m.body AS msg_body 
    ,m.created_at 
FROM messages m 
INNER JOIN users sender 
ON sender.id = m.sender_user_id 
INNER JOIN users recipient 
ON recipient.id = m.recipient_user_id 
INNER JOIN users owner 
ON owner.id = m.user_id 
+0

Благодарим вас за ответ и подробное объяснение. Ответ Mureinik также является тем, что я искал, но я бы принял ваш как «правильный», потому что он немного информативен. Спасибо! – user1330974

+0

@onedaywhen Сравнивая план 'EXPLAIN' в SQLFiddle для каждого запроса, вы можете увидеть разницу. Тем не менее, вы правы, он не обязательно запрашивает самые внутренние строки. В каждой ситуации, которую я испытал, когда кто-то создает запрос, подобный OP, он выполняет значительно хуже, чем прямое соединение. См. Также https://dev.mysql.com/doc/refman/5.6/en/subquery-optimization.html. Я позже буду обновлять свой ответ (рабочие вызовы), подробно описывая, как «ref» и «ALL» в плане объяснения OP означают, что производительность хуже, чем «eq_ref» в плане объяснения моего запроса. –

1

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

SELECT m.id, 
     m.user_id AS msg_owner, 
     o.name AS msg_owner_name, 
     m.sender_user_id, 
     s.name, 
     m.recipient_user_id, 
     r.name AS recipient_name, 
     m.body, 
     m.created_at 
FROM messages m 
JOIN users o ON m.user_id = o.id 
JOIN users s ON m.sender_user_id = s.id 
JOIN users r ON m.recipient_user_id = r.id 
+0

Ударьте меня по секундам. –

+0

@Mureinik Спасибо, что ответили на мой вопрос! Теперь я знаю, что это возможно для многих пользователей, таких как INNER JOIN. Я принял ответ Виллема, потому что он объяснил немного больше о производительности и подумал, что это может быть полезно для других начинающих SQL, таких как я. :) – user1330974