2011-12-16 101 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);