Оптимизация запросов MySQL - PullRequest
0 голосов
/ 10 апреля 2011

Просто интересно, как лучше написать этот запрос.Приветствия.

SELECT r.user_id AS ID, m.prenom, m.nom
FROM `0_rank` AS l
LEFT JOIN `0_right` AS r ON r.rank_id = l.id
LEFT JOIN `0_user` AS m ON r.user_id = m.id
WHERE r.section_id = $section_id
AND l.rank = '$rank_name' AND depart_id IN 
(SELECT depart_id FROM 0_depart WHERE user_id = $user_id AND section_id = $section_id) 
GROUP BY r.user_id

Вот структуры таблиц:

  • 0_rank: id |section_id |ранг_имя |other_stuffs
  • 0_пользователь: id |Преном |ном |other_stuffs
  • 0_right: id |section_id |user_id |rank_id |other_stuffs
  • 0_доставка: id |section_id |user_id |отправление |other_stuffs

Идея состоит в том, чтобы использовать то же самое в такой функции, как:

public function usergroup($section_id,$rank_name,$user_id) { 
 // mysql query goes here to get a list of appropriate users
}

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

SELECT m.id, m.prenom, m.nom, 
CAST( GROUP_CONCAT( DISTINCT d.depart ) AS char ) AS deps, 
CAST( GROUP_CONCAT( DISTINCT x.depart ) AS char ) AS depx
FROM `0_rank` AS l
LEFT JOIN `0_right` AS r ON r.rank_id = l.id
LEFT JOIN `0_member` AS m ON r.user_id = m.id
LEFT JOIN `0_depart` AS d ON m.id = d.user_id
LEFT JOIN `0_depart` AS x ON x.user_id = $user_id
WHERE r.section = $section_id
AND l.rank = '$rank_name'
GROUP BY r.user_id ORDER BY prenom, nom

Теперь я хочу получить только тот результат, где все записи deps присутствуют в записях в depx.

В другихТермин, каждый пользователь связан с некоторыми отходами.$ user_id - это также пользователь, связанный с некоторыми вылетами.

Я хочу получить тех пользователей, чьи вылеты являются общими для вылетов из $ user_id.

Cheers.

Ответы [ 4 ]

1 голос
/ 10 апреля 2011

Обновление

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

SELECT m.id, m.prenom, m.nom, 
CAST( GROUP_CONCAT( DISTINCT d.depart ) AS char ) AS deps, 
FROM `0_rank` AS l
LEFT JOIN `0_right` AS r ON r.rank_id = l.id and r.user_id = $user_id
LEFT JOIN `0_member` AS m ON r.user_id = m.id
LEFT JOIN `0_depart` AS d ON m.id = d.user_id
WHERE r.section = $section_id
AND l.rank = '$rank_name'
GROUP BY r.user_id ORDER BY prenom, nom

Дайте мне знать, если это работает.


Попробуйте это: (Преобразовав функциональность IN (SELECT ...) во внутреннее соединение, вы получите точно такие же результаты, но это может бытьоптимизатор сделает лучший выбор.)

SELECT r.user_id AS ID, m.prenom, m.nom
FROM `0_rank` AS l
LEFT JOIN `0_right` AS r ON r.rank_id = l.id and r.section_id = 2
LEFT JOIN `0_user` AS m ON r.user_id = m.id
INNER JOIN `0_depart` AS x ON l.section_id = x.section_id and x.user_id = $user_id AND x.section_id = $section_id
WHERE l.rank = 'mod' 
GROUP BY r.user_id

Я также переместил ограничения на 0_right в оператор соединения, потому что я думаю, что он более понятен - возможно, это изменение не будет иметь значения для оптимизатора.

1 голос
/ 10 апреля 2011

Я ничего не знаю о вашей структуре БД, но ваш подвыбор выглядит так, как будто его можно заменить простым INNER JOIN для любой таблицы со столбцом depart. MySQL хорошо известен своей плохой оптимизацией подзапроса.

1 голос
/ 10 апреля 2011

Не зная структур или индексов, я сначала добавил бы «STRAIGHT_JOIN», если критический критерий фактически из таблицы 0 рангов. Затем убедитесь, что 0_rank имеет индекс «rank». Далее, убедитесь, что у 0_right есть индекс как минимум для rank_id, но есть раздел rank_id, чтобы воспользоваться ОБА вашими критериями. Индекс 0_member по идентификатору.

Кроме того, вы имеете в виду левое соединение (то есть: запись требуется только в 0_rank или 0_member) в соответствующих таблицах 0_right и 0_member вместо обычного соединения (где ОБА таблицы должны совпадать по своим идентификаторам).

Наконец, убедитесь, что индекс для таблицы отъезда указан в user_id.

SELECT STRAIGHT_JOIN 
        r.user_id AS ID, 
        m.prenom, 
        m.nom
    FROM 
        0_rank AS l
            LEFT JOIN `0_right` AS r 
                ON l.id = r.rank_id 
                AND r.section = 2
            LEFT JOIN `0_member` AS m 
                ON r.user_id = m.id
    WHERE 
          l.rank = 'mod' 
      AND depart IN (SELECT depart 
                       FROM 0_depart 
                      WHERE user_id = 2 
                        AND user_sec = 2) 
    GROUP BY 
       r.user_id

---- исправлено сообщение из отзыва. Из параметров, которые вы перечисляете, вы всегда включаете идентификатор пользователя ... Если это так, я бы полностью реструктурировал его, чтобы получить любую информацию для этого пользователя. Очевидно, что каждый пользователь может быть связан с несколькими отделами и может или не может соответствовать заданному разряду / отделу / разделу, который вы ищете ... Я бы НАЧАЛ запрос с ОДНОГО ПОЛЬЗОВАТЕЛЯ, потому что ЭТО гарантирует одну запись, ТО вплоть до других элементов ...

select STRAIGHT_JOIN
        u.id,
        u.prenom,
        u.nom,
        u.other_stuffs,
        rank.rank_name
    from 
        0_user u

            left join 0_right r
                 on u.id = r.user_id
                AND r.section_id = $section_id

                join 0_rank rank
                    on r.rank_id = rank.id
                    AND rank.rank_name = '$rank_name'

            left join 0_dept dept
                on u.id = dept.user_id
    where 
        u.id = $user_id

Кроме того, я беспокоюсь о ваших отношениях за столом и не вижу законного соединения с таблицей отдела ...

0_user
   0_right by User_ID
      0_rank by right.rank_id


0_dept has section which could join to rank or right, but nothing to user_id directly
0 голосов
/ 10 апреля 2011

Запустите объяснение по запросу - это поможет вам найти, где предостережения:

EXPLAIN SELECT r.user_id AS ID, m.prenom, m.nom
FROM 0_rank AS l
LEFT JOIN `0_right` AS r ON r.rank_id = l.id
LEFT JOIN `0_member` AS m ON r.user_id = m.id
WHERE r.section = 2
AND l.rank = 'mod' AND depart IN 
(SELECT depart FROM 0_depart WHERE user_id = 2 AND user_sec = 2) 
GROUP BY r.user_id\G
...