2013-10-01 3 views
0

У меня есть запрос, который занимает несколько минут, чтобы выполнить на небольшом наборе данных, в чем проблема? вот объяснить выход:Mysql Плохая производительность запросов со многими объединениями

id select_type table   type possible_keys    key     key_len ref    rows Extra 

1 SIMPLE  BT_CALL_CLASS.. const PRIMARY      PRIMARY    4   const   1  Using index; Using temporary; Using filesort 
1 SIMPLE  BT_FLAGS_FLAGS const PRIMARY      PRIMARY    4   const   1  Using index 
1 SIMPLE  BT_DIRECTORY... range PRIMARY      PRIMARY    4   NULL   308 Using where; Using index 
1 SIMPLE  BT_CALL_FLAGS.. ref  PRIMARY,FKDF68A2ED9F150002 FKDF68A2ED9F150002 4   const   49 Using where; Using index 
1 SIMPLE  BT_DEPARTMENT.. index PRIMARY      FK1F3A276188DDBD3 5   NULL   27 Using where; Using index; Using join buffer 
1 SIMPLE  BT_USERS_USER.. index PRIMARY      FK6A68E086C27A155 5   NULL   233 Using where; Using index; Using join buffer 
1 SIMPLE  BT_FCT_CALLS.. eq_ref PRIMARY,FKDF68A2ED4F28.. PRIMARY    8   ...call_id  1  Using where 

Запрос

desc SELECT DISTINCT 
     BT_FCT_CALLS_FCT_CALLS.start_time AS COL0 
    ,BT_FCT_CALLS_FCT_CALLS.calling_number AS COL1 
    ,BT_FCT_CALLS_FCT_CALLS.called_number AS COL2 
    ,BT_FCT_CALLS_FCT_CALLS.response AS COL3 

FROM departments BT_DEPARTMENTS_DEPARTMENTS_3 LEFT OUTER JOIN 
( 
    directory_numbers BT_DIRECTORY_NUMBERS_DIRECTORY_NUMBERS LEFT OUTER JOIN 
    ( 
    users BT_USERS_USERS_2 JOIN 
    ( 
    call_classification_dim BT_CALL_CLASSIFICATION_DIM_CALL_CLASSIFICATION_DIM JOIN 
    ( 
    flags BT_FLAGS_FLAGS JOIN 
    ( 
     fct_calls BT_FCT_CALLS_FCT_CALLS JOIN call_flags BT_CALL_FLAGS_CALL_FLAGS 
     ON (BT_FCT_CALLS_FCT_CALLS.id = BT_CALL_FLAGS_CALL_FLAGS.call_id) 
    ) 
    ON (BT_CALL_FLAGS_CALL_FLAGS.flag = BT_FLAGS_FLAGS.id AND ( BT_FLAGS_FLAGS.id = 1) ) 
    ) 
    ON (BT_FCT_CALLS_FCT_CALLS.call_direction_id = BT_CALL_CLASSIFICATION_DIM_CALL_CLASSIFICATION_DIM.id AND ( BT_CALL_CLASSIFICATION_DIM_CALL_CLASSIFICATION_DIM.id = 2) ) 
    ) 
    ON (((BT_FCT_CALLS_FCT_CALLS.on_network_called_user_id = BT_USERS_USERS_2.id) OR (BT_FCT_CALLS_FCT_CALLS.on_network_calling_user_id = BT_USERS_USERS_2.id)) AND TRUE ) 
) 
    ON (((BT_FCT_CALLS_FCT_CALLS.on_network_called_ext_id = BT_DIRECTORY_NUMBERS_DIRECTORY_NUMBERS.id) OR (BT_FCT_CALLS_FCT_CALLS.on_network_calling_ext_id = BT_DIRECTORY_NUMBERS_DIRECTORY_NUMBERS.id)) AND TRUE) 
) 
ON (((BT_FCT_CALLS_FCT_CALLS.on_network_called_department_id = BT_DEPARTMENTS_DEPARTMENTS_3.id) OR (BT_FCT_CALLS_FCT_CALLS.on_network_calling_department_id = BT_DEPARTMENTS_DEPARTMENTS_3.id)) AND TRUE) 

    WHERE 
    (
     (
      NOT(BT_DEPARTMENTS_DEPARTMENTS_3.id IN (1)) 
    ) 
    AND (
      NOT(BT_DIRECTORY_NUMBERS_DIRECTORY_NUMBERS.id IN (1)) 
    ) 

    AND (
      NOT(BT_USERS_USERS_2.id IN (1)) 
    ) 
    ) 
ORDER BY 
     COL0 
+4

Может быть много объяснений (индексы, объединение, ...), и это невозможно сказать, не доведя запрос. Даже тогда это может быть сложно ... –

+0

Каков запрос? – davey

+0

Проблема в том, что у нас нет запроса. – Mihai

ответ

0

Как я уже сказал в комментарии, запросы автоматически сгенерированы, и я не могу их модифицировать, так или иначе, после обновления до mysql 5.6.14 и без каких-либо изменений, что когда-либо было в самом запросе, производительность стала нормальный (по сравнению с другими запросами с аналогичной сложностью)!

0

Чтобы начать с изменения вашего ИНЕКЕ:

WHERE 
BT_DEPARTMENTS_DEPARTMENTS_3.id <> 1 AND 
BT_DIRECTORY_NUMBERS_DIRECTORY_NUMBERS.id <> 1 AND 
BT_USERS_USERS_2.id <> 1 

Это быстрее, чем при использовании NOT IN (..)

Удалить AND TRUE не нужно.

+0

Правда, но все же это не то, что вызывает проблему. –

0

Во-первых, давайте начнем с очень плохо написанного потока запроса. Упрощая непосредственные отношения и все ваше гнездование может помочь прояснить некоторые вещи. Во-вторых, покажите отношения вниз по дереву, что вещи связаны. Вы подпрыгиваете повсюду. Я также сократил «псевдонимы» для удобства чтения. Наконец, вам не нужны все таблицы, поскольку вы не получаете значений из всех таблиц, которые делают много вещей бесполезными. Во всяком случае, это чистая версия вашего исходного запроса. Как вы можете видеть, намного легче видеть, где таблица A ссылки на B ссылки на ссылки C до D и т.д.

SELECT DISTINCT 
     calls.start_time AS COL0, 
     calls.calling_number AS COL1, 
     calls.called_number AS COL2, 
     calls.response AS COL3 
    FROM 
     fct_calls calls 
     JOIN departments dpt3 
      ON calls.on_network_called_department_id = dpt3.id 
      OR calls.on_network_calling_department_id = dpt3.id 
     JOIN users u2 
      ON calls.on_network_called_user_id = u2.id 
      OR calls.on_network_calling_user_id = u2.id 
     JOIN directory_numbers dirNums 
      ON calls.on_network_called_ext_id = dirNums.id 
      OR calls.on_network_calling_ext_id = dirNums.id 
     JOIN call_classification_dim classDim 
      ON calls.call_direction_id = classDim.id 
      AND classDim.id = 2 
     JOIN call_flags callFlags 
      ON calls.id = callFlags.call_id 
      JOIN flags f 
       ON callFlags.flag = f.id 
       AND f.id = 1 
    WHERE 
     dpt3.id <> 1 
    AND dirNums.id <> 1 
    AND u2.id = 1 
    ORDER BY 
    COL0 

Теперь, вот что я хотел бы работать с. Опять же, многие вещи даже не используются, такие как флаги вызовов и номера каталогов. Начните со всех вызовов, у которых есть идентификатор пользователя, который вас интересует, с помощью либо вызывающей, либо вызываемой позиции. У меня был бы индекс в таблице вызовов (on_network_called_user_id, on_network_calling_user_id). Я бы предположил, что другие таблицы имеют индексы в своих соответствующих первичных столбцах «ИД».

SELECT DISTINCT 
     calls.start_time AS COL0, 
     calls.calling_number AS COL1, 
     calls.called_number AS COL2, 
     calls.response AS COL3 
    FROM 
     fct_calls calls 
     JOIN departments dpt3 
      ON calls.on_network_called_department_id = dpt3.id 
      OR calls.on_network_calling_department_id = dpt3.id 
     JOIN directory_numbers dirNums 
      ON calls.on_network_called_ext_id = dirNums.id 
      OR calls.on_network_calling_ext_id = dirNums.id 
    WHERE 
    ( calls.on_network_called_user_id = 1 
     OR calls.on_network_calling_user_id = 1) 
    AND dpt3.id <> 1 
    AND dirNums.id <> 1 
    ORDER BY 
    COL0 

Принимая это шаг вперед, вы можете получить более высокую производительность, делая UNION в связи с рассмотрением либо вызова или вызывается, вы можете попробовать следующее. Таким образом, вы ищете любой вызов, в котором лицо, выполняющее вызов, является идентификатором пользователя 1, а вызванный отдел НЕ является 1, а расширение каталога НЕ 1 ... Или пользовательский идентификатор 1 вызывается, но игнорирует его из департамента 1 и расширение 1.

Я бы ДВА индексов в таблице вызовов для Этот один для тех, кто вызывается, и ГДЕ, чТО ПРИЗЫВ происходит от (on_network_called_user_id, on_network_calling_department_id, on_network_calling_ext_id) Этот реверс ... кто звонит и чТО Отдел/Extension они называют (on_network_calling_user_id, on_network_called_department_id, on_network_called_ext_id)

SELECT 
     calls.start_time AS COL0, 
     calls.calling_number AS COL1, 
     calls.called_number AS COL2, 
     calls.response AS COL3 
    FROM 
     fct_calls calls 
     LEFT JOIN departments dpt3 
      OR calls.on_network_calling_department_id = dpt3.id 
     LEFT JOIN directory_numbers dirNums 
      OR calls.on_network_calling_ext_id = dirNums.id 
    WHERE 
      calls.on_network_called_user_id = 1 
     AND calls.on_network_calling_department_id <> 1 
     AND calls.on_network_calling_ext_id <> 1 
    ORDER BY 
     COL0 
UNION 
SELECT 
     calls.start_time AS COL0, 
     calls.calling_number AS COL1, 
     calls.called_number AS COL2, 
     calls.response AS COL3 
    FROM 
     fct_calls calls 
     LEFT JOIN departments dpt3 
      OR calls.on_network_called_department_id = dpt3.id 
     LEFT JOIN directory_numbers dirNums 
      OR calls.on_network_called_ext_id = dirNums.id 
    WHERE 
      calls.on_network_calling_user_id = 1 
     AND calls.on_network_called_department_id <> 1 
     AND calls.on_network_called_ext_id <> 1 
Смежные вопросы