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

#mysql

#mysql

Вопрос:

 select 
    b.entry_id,
    b.assign_id,
    a.profile_type,
    a.profile_id,
    a.profile_name,
    a.profile_status,
    b.entry_type,
    b.assign_id,
    c.chapter_name,
    d.section_name,
    h.group_name,
    i.programme_name,
    k.subjectprogramme_name,
    j.masterprogramme_name,
    l.developmentprogramme_name
from profile_master a
left join profile_assign b on (a.profile_id = b.profile_id)  
left join chapter_master c 
       on (b.entry_id = c.chapter_id and b.entry_type='chapter') 
left join section_master d 
       on (b.entry_id = d.section_id and b.entry_type='section')
left join group_master h 
       on (b.entry_id = h.group_id and b.entry_type='Group' 
           and h.year_id='".$this->year."')
left join programme_master i 
       on (b.entry_id = i.programme_id and b.entry_type='Programme' 
           and i.year_id='".$this->year."')
left join subjectprogramme_master k 
       on (b.entry_id = k.subjectprogramme_id and b.entry_type='subjectProgramme' 
           and k.year_id='".$this->year."')
left join masterprogramme_master j 
       on (b.entry_id = j.masterprogramme_id and b.entry_type='masterProgramme' 
           and j.year_id='".$this->year."')
left join developmentprogramme_master l 
       on (b.entry_id = l.developmentprogramme_id 
           and b.entry_type='developmentProgramme')
  

Комментарии:

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

2. если я создам индекс для profile_id для таблицы profile_assign, spp будет увеличен, это правильный способ

Ответ №1:

1) Избавьтесь от where coditions из left join. Используйте предложение WHERE для фильтрации

2) Я думаю, что ОБЪЕДИНЕНИЕ или 7 запросов (по каждому объекту отдельно) будут намного лучше в вашем случае

Ответ №2:

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

  • Используйте «explain» в этом запросе, чтобы узнать, предлагает ли MySQL какие-либо индексы. Без сомнения, это предложит несколько, потому что вы обращаетесь к нескольким столбцам несколько раз, и часто индексы улучшаются даже самые медленные OUTER JOIN
  • Вы используете множество проверок $this->year , так что это предполагает некоторые составные индексы, где, например, programme_id и year_id находятся в одном и том же индексе

Конечно, есть решения, которые могут зависеть от того, как вы используете выходные данные, например:

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

Ответ №3:

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

 SELECT 
    b.entry_id, 
    b.assign_id, 
    a.profile_type, 
    a.profile_id, 
    a.profile_name, 
    a.profile_status, 
    b.entry_type, 
    b.assign_id, 
    CASE b.entry_type 
    WHEN 'chapter' THEN SELECT(c.chapter_name FROM c WHERE b.entry_id = c.chapter_id)
    WHEN 'section' THEN SELECT(d.section_name FROM d WHERE b.entry_id = d.section_id)
    WHEN ....
    END as name
from profile_master a 
left join profile_assign b on (a.profile_id = b.profile_id)   
  

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

 SELECT 
  entry_id, assign_id, ......
  , CASE entry_type WHEN 'chapter' THEN name ELSE null END as chapter_name
  , CASE entry_type WHEN 'section' THEN name ELSE null END as section_name
FROM
  (select statement like above) sub