2010-01-22 79 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版本无法进行索引合并。