MySQL, читая это заявление EXPLAIN - PullRequest
5 голосов
/ 21 октября 2008

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

            +----+-------------+-------+--------+---------------+------------+---------+-------------------------------+------+---------------------------------+
            | id | select_type | table | type   | possible_keys | key        | key_len | ref                           | rows | Extra                           |
            +----+-------------+-------+--------+---------------+------------+---------+-------------------------------+------+---------------------------------+
            |  1 | SIMPLE      | s     | ref    | client_id     | client_id  | 4       | const                         |  102 | Using temporary; Using filesort |
            |  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY    | 4       | www_foo_com.s.user_id         |    1 |                                 |
            |  1 | SIMPLE      | a     | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 | Using index                     |
            |  1 | SIMPLE      | h     | ref    | email_id      | email_id   | 4       | www_foo_com.a.email_id        |   10 | Using index                     |
            |  1 | SIMPLE      | ph    | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 | Using index                     |
            |  1 | SIMPLE      | em    | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 |                                 |
            |  1 | SIMPLE      | pho   | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 |                                 |
            |  1 | SIMPLE      | c     | ALL    | userfield     | NULL       | NULL    | NULL                          | 1108 |                                 |
            +----+-------------+-------+--------+---------------+------------+---------+-------------------------------+------+---------------------------------+
            8 rows in set (0.00 sec)

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

Похоже, что сканирование ALL против таблицы 'c' - это ахиллесова пята. Каков наилучший способ индексировать это на основе постоянных значений, как рекомендуется в документации MySQL? |

Обратите внимание, я также добавил индекс в поле пользователя в таблице cdr, и это тоже не принесло пользы.

Спасибо.

--- редактировать ---

Вот запрос, извините - не знаю, почему я не включил его в первый проход.

SELECT s.`session_id` id,
                  DATE_FORMAT(s.`created`,'%m/%d/%Y') date,
                  u.`name`,
                  COUNT(DISTINCT c.id) calls,
                  COUNT(DISTINCT h.id) emails,
                  SEC_TO_TIME(MAX(DISTINCT c.duration)) duration,
                  (COUNT(DISTINCT em.email_id) + COUNT(DISTINCT pho.phone_id) > 0) status
           FROM `fa_sessions` s
           LEFT JOIN `fa_users` u ON s.`user_id`=u.`user_id`
           LEFT JOIN `fa_email_aliases` a ON a.session_id = s.session_id
           LEFT JOIN `fa_email_headers` h ON h.email_id = a.email_id
           LEFT JOIN `fa_phones` ph ON ph.session_id = s.session_id
           LEFT JOIN `fa_email_aliases` em ON em.session_id = s.session_id AND em.status = 1
           LEFT JOIN `fa_phones` pho ON pho.session_id = s.session_id AND pho.status = 1
           LEFT JOIN `cdr` c ON c.userfield = ph.phone_id
           WHERE s.`partner_id`=1
           GROUP BY s.`session_id`      

Ответы [ 4 ]

3 голосов
/ 21 октября 2008

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

Со страницы:

Использование сортировки файлов

MySQL должен сделать дополнительный проход, чтобы найти узнать, как получить строки в отсортированном порядок. Сортировка делается путем перехода через все строки в соответствии с соединением введите и сохраните ключ сортировки и указатель на строку для всех строк, которые соответствовать предложению WHERE. Ключи тогда сортируются и строки извлекаются в отсортированном порядке. См. Раздел 7.2.12, «ЗАКАЗАТЬ ПО ОПТИМИЗАЦИИ».

Использование временного

Для разрешения запроса MySQL необходимо создать временную таблицу для хранения результат. Обычно это происходит, если запрос содержит GROUP BY и ORDER BY пункты, которые перечисляют столбцы по-разному.

Я согласен с тем, что просмотр запроса может помочь лучше разобраться.

3 голосов
/ 21 октября 2008

Мой совет?

Разбейте запрос на 2 и используйте временную таблицу в середине.

Reasonning

Проблема заключается в том, что таблица c сканируется и что это последняя таблица в запросе. Это, вероятно, плохо: если у вас есть сканирование таблицы, вы хотите сделать это в начале запроса, так что это делается только один раз.

Я не гуру MySQL, но я потратил много времени на оптимизацию запросов к другим БД. Мне кажется, что оптимизатор не сработал, что он должен начинаться с c и работать в обратном направлении.

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

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

Общие советы

Не стесняйтесь смотреть этот ответ Я дал общие советы по производительности.

Отличный ресурс

Документация MySQL для EXPLAIN

2 голосов
/ 21 октября 2008

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

1 голос
/ 22 октября 2008

План запроса

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

  • начать с sessions, где partner_id=1, возможно, используя индекс для partner_id,
  • объединить sessions с users, используя индекс на user_id
  • присоединить sessions к phones, где status=1, используя индекс для session_id и, возможно, status
  • соедините sessions с phones снова, используя индекс для session_id и phone_id **
  • присоединить phones к cdr с помощью индекса на userfield
  • присоединить sessions к email_aliases, где status=1 с использованием индекса на session_id и, возможно, status
  • соедините sessions с email_aliases снова, используя индексы session_id и email_id **
  • присоединить email_aliases к email_headers с помощью индекса на email_id

**, поместив 2 поля в эти индексы, мы позволяем оптимизатору присоединиться к таблице, используя session_id, и немедленно найти связанный phone_id или email_id, не считывая базовую таблицу. Эта техника экономит нам чтение и может сэкономить много времени.

Индексы, которые я бы создал:

Приведенный выше план запроса предлагает следующие значения:

fa_sessions ( partner_id, session_id )  
fa_users ( user_id )  
fa_email_aliases ( session_id, email_id )  
fa_email_headers ( email_id )  
fa_email_aliases ( session_id, status )  
fa_phones ( session_id, status, phone_id ) 
cdr ( userfield ) 

Примечания

  • Вы почти наверняка получите приемлемую производительность, не создавая все это.
  • Если какая-либо из таблиц небольшая (менее 100 строк), то, вероятно, не стоит создавать индекс.
  • fa_email_aliases может работать с ( session_id, status, email_id ), в зависимости от того, как работает оптимизатор.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...