2010-01-22 78 views
4

這是我表演(不包括某些連接不相關)查詢:MySQL的GROUP BY性能問題

SELECT a.*, c.id 
FROM a 
LEFT OUTER JOIN b ON a.id = b.id_anunciante 
LEFT OUTER JOIN c ON c.id = b.id_rubro 
GROUP BY a.id 

的「一」與1至5行的「B」連接每行。

問題是GROUP BY存在性能問題(使用GROUP BY需要10倍或更多比不使用它)。我需要只檢索「a」中每個成員的一行。

我該如何讓這個更快?

編輯:我需要能夠通過a.id和/或c.id進行過濾。我應該得到的結果集是「a」的每個「有效」成員只有1行,這意味着匹配約束的行。不匹配過濾器的行不應返回。 我在原來的查詢,就可以這樣做是這樣的:

SELECT a.*, c.id 
FROM a 
LEFT OUTER JOIN b ON a.id = b.id_anunciante 
LEFT OUTER JOIN c ON c.id = b.id_rubro 
WHERE c.id = 1 
OR a.id = 1 
GROUP BY a.id 

a.id,b.id_anunciante,b.id_rubro,c.id都是索引。

回答

5
SELECT a.*, 
     (
     SELECT c.id 
     FROM b 
     JOIN с 
     ON  c.id = b.id_rubro 
     WHERE b.id_anunciante = a.id 
     -- add the ORDER BY condition to define which row will be selected. 
     LIMIT 1 
     ) 
FROM a 

這個創建於b (id_anunciante)索引工作得更快。

更新:

你不需要在這裏OUTER JOINs

重寫查詢,因爲這:

SELECT a.*, c.id 
FROM a 
JOIN b 
ON  b.id_anunciante = a.id 
JOIN c 
ON  c.id = b.id_rubro 
WHERE a.id = 1 
UNION ALL 
SELECT a.*, 1 
FROM a 
WHERE EXISTS 
     (
     SELECT NULL 
     FROM c 
     JOIN b 
     ON  b.id_rubro = c.id 
     WHERE c.id = 1 
       AND b.id_anunciante = a.id 
     ) 
+0

感謝您的回答! 如果我需要通過c.id和/或a.id進行過濾,該怎麼辦?我不能這樣做,我可以嗎? – Gerardo 2010-01-23 18:58:43

+0

'@ macaco':當然可以。只需在外部查詢中添加一個WHERE條件以過濾「a」,並在子查詢中過濾「c」。 – Quassnoi 2010-01-23 20:56:34

+0

我試圖通過子查詢「WHERE b.id_anunciante = a.id AND c.id = 1」中的c.id進行過濾,但是我得到了相同數量的行,並且那些不應該與子查詢列一起填充的行與NULL。 – Gerardo 2010-01-25 23:00:50

0

添加ORDER BY NULL避免隱性排序的MySQL做一組什麼時候。

我想你有在a.id,b.id_anunciante,b.id_rubro和c.id上的索引/ PKs?我想你可以嘗試在(b.id_anunciante,b.id_rubro)上添加一個複合索引,如果你的mysql版本無法進行索引合併。