2013-10-01 41 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子句:

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

首先,讓我們從查詢流程非常差的文章開始。通過簡化直接的關係vs你所有的嵌套可以幫助清除一些事情。其次,展示事物相關的樹之間的關係。你正在反彈。爲了提高可讀性,我還縮短了「別名」。最後,你不需要所有的表格,因爲你沒有從所有表格中獲取值,這使得許多事情變得毫無用處。無論如何,這裏是你的原始查詢的清理版本。正如你所看到的,看到更容易,其中表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 

現在,這裏是我會與運行。再次,許多事情甚至沒有被使用,例如呼叫標誌和目錄號碼。從所有具有您感興趣的用戶ID的呼叫開始,通過呼叫或被叫位置。我將在(on_network_called_user_id,on_network_calling_user_id)上的調用表上有一個索引。我會假設其他表在他們各自的主「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由於考慮到無論是打電話還是被調用,您可以嘗試以下獲得更好的性能。因此,您正在查找打電話的人是用戶ID 1且呼叫的部門不是1而目錄擴展不是1的任何呼叫。或者,用戶ID 1正在呼叫,但忽略來自部門1和擴展1.

我會對調用表中的兩個索引 這一個誰被調用,而且該CALL源於 (on_network_called_user_id,on_network_calling_department_id,on_network_calling_ext_id) 此相反的......是誰打來的,以及他們撥打的電話號碼是 (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