2011-12-16 130 views
1

我有一個查詢通過使用LEFT JOIN和子查詢從多個表中獲取計數。這個想法是讓activites成員曾參加過各種計數多個左連接的MySQL計數 - optomization

的模式是這樣的:

成員 PK member_id

table1的 PK tbl1_id FK member_id

表2 PK tbl2_id FK member_id

table3 PK tbl 3_id FK member_id

我的查詢看起來是這樣的:

SELECT t1.num1,t2.num2,t3.num3 
FROM member m 
LEFT JOIN 
(
    SELECT member_id,COUNT(*) as num1 
    FROM table1 
    GROUP BY member_id 
) t1 ON t1.member_id = m.member_id 
LEFT JOIN 
(
    SELECT member_id,COUNT(*) as num2 
    FROM table2 
    GROUP BY member_id 
) t2 ON t2.member_id = m.member_id 
LEFT JOIN 
(
    SELECT member_id,COUNT(*) as num3 
    FROM table3 
    GROUP BY member_id 
) t3 ON t3.member_id = m.member_id 
WHERE m.member_id = 27 

其中27是一個測試ID。實際的查詢連接三個以上的表,並且在更改member_id的情況下多次運行查詢。問題是這個查詢運行速度很慢。我得到我需要的信息,但我想知道是否有人可以提出一種方法來優化這一點。任何建議非常感謝。非常感謝。

+0

你對所有這些表的索引是什麼? – MatBailie 2011-12-16 16:37:59

回答

3

你應該重構你的查詢。您可以通過重新排序查詢收集數據的方式來做到這一點。怎麼樣?

  • 應用WHERE子句第一
  • 申請加入上次

這裏是你的原始查詢:

SELECT t1.num1,t2.num2,t3.num3 
FROM member m 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num1 
    FROM table1 
    GROUP BY member_id 
) t1 ON t1.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num2 
    FROM table2 
    GROUP BY member_id 
) t2 ON t2.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num3 
    FROM table3 
    GROUP BY member_id 
) t3 ON t3.member_id = m.member_id 
WHERE m.member_id = 27 

這裏是你新的查詢

SELECT 
    IFNULL(t1.num1,0) num1, 
    IFNULL(t1.num2,0) num2, 
    IFNULL(t1.num3,0) num3 
FROM 
(
    SELECT * FROM member m 
    WHERE member_id = 27 
) 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num1 
    FROM table1 
    WHERE member_id = 27 
    GROUP BY member_id 
) t1 ON t1.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num2 
    FROM table2 
    WHERE member_id = 27 
    GROUP BY member_id 
) t2 ON t2.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num3 
    FROM table3 
    WHERE member_id = 27 
    GROUP BY member_id 
) t3 ON t3.member_id = m.member_id 
; 

BTW我改爲member m轉換爲SELECT * FROM member m WHERE member_id = 27以防您需要有關成員27的任何信息。我​​還爲每個結果添加了IFNULL函數,以便在count爲NULL的情況下生成0。

你需要絕對確保

  • member_id是成員表
  • member_id在表1,表2索引的主鍵,表3

試試看! !

2

不知道你的架構和你爲指標做了什麼,一個可能的方式,使這個速度是:

SELECT (select ifnull(count(*),0) from table1 where table1.member_id = m.id) as num1, 
(select ifnull(count(*),0) from table2 where table2.member_id = m.id) as num2, 
(select ifnull(count(*),0) from table3 where table3.member_id = m.id) as num3 
from member m 
WHERE m.member_id = 27 

現在,這是一個稍微高風險的建議,只是因爲我什麼都不知道關於您的數據庫或其他什麼運行,或瓶頸在哪裏。

一般來說,最好是在您的查詢中發佈解釋計劃以獲得更好的答案。

+0

與OPs格式的JOIN相比,相關的子查詢很少有效地執行。事實上,如果OP寫了這裏給出的例子,我會建議OP目前使用的格式。 – MatBailie 2011-12-16 17:00:17

+0

@Dems - 至少在我的測試系統中有機磷農藥格式導致了表1,表2和表3,在我的建議正確使用索引全表掃描。 – 2011-12-16 17:12:22

0
SELECT num1, num2, count(*) as num3 
FROM (
    SELECT member_id, num1, count(*) as num2 
    FROM (
    SELECT member_id, count(*) as num1 
    FROM member 
    LEFT JOIN table1 USING (member_id) 
    WHERE member_id = 27) as m1 
    LEFT JOIN table2 USING (member_id)) as m2 
LEFT JOIN table3 USING (member_id);