Mysql 具有左联接的多表上SQL查询的优化

Mysql 具有左联接的多表上SQL查询的优化,mysql,sql,Mysql,Sql,我已经创建了一个定制的mysql查询,它运行良好,显示了我想要的输出,但由于数据量很大,目前需要花费大量时间 所以,请帮助我优化查询运行时 SELECT t.*, te + tc + tt AS total, (te + tc + tt)/7 AS weekly_Avg FROM (SELECT t2.first_name, COUNT(DISTINCT emails.id) AS te, COUNT(DISTINCT calls.id) AS tc, COUNT(DISTINC

我已经创建了一个定制的mysql查询,它运行良好,显示了我想要的输出,但由于数据量很大,目前需要花费大量时间

所以,请帮助我优化查询运行时

SELECT t.*, te + tc + tt AS total, (te + tc + tt)/7 AS weekly_Avg
FROM (SELECT t2.first_name, COUNT(DISTINCT emails.id) AS te,
        COUNT(DISTINCT calls.id) AS tc, COUNT(DISTINCT tasks.id) AS tt
      FROM users AS t2
      LEFT JOIN emails
        ON t2.id = emails.assigned_user_id
        AND emails.date_entered >= '2014-03-20 00:00:00'
        AND emails.date_entered <= '2014-06-30 00:00:00'
      LEFT JOIN calls
        ON t2.id = calls.assigned_user_id
        AND calls.date_entered >= '2014-03-20 00:00:00'
        AND calls.date_entered <= '2014-06-30 00:00:00'
      LEFT JOIN tasks
        ON t2.id = tasks.assigned_user_id
        AND tasks.date_entered >= '2014-03-20 00:00:00'
        AND tasks.date_entered <= '2014-06-30 00:00:00')
      WHERE t2.id IN ('1', '2')
      GROUP BY t2.id) t

在这段时间内,每个用户有多少电话/电子邮件/任务?这个查询实际上是对结果进行交叉连接,因此,如果每个用户有100条记录,那么每个用户将有1000000条记录,然后在该列表中对唯一的记录进行排序

如果是这样的话,使用子查询获取每个计数并将结果连接在一起可能会更容易

SELECT t . * ,te+tc+tt as total , (,te+tc+tt)/7 as weekly_Avg
FROM 
(
    SELECT t2.first_name, emails_count AS te, calls_count AS tc, tasks_count AS tt
    FROM  `users` AS t2
    LEFT JOIN 
    (
        SELECT assigned_user_id, COUNT( emails.id ) AS emails_count
        FROM emails 
        WHERE emails.assigned_user_id IN ( '1',  '2')
        AND (emails.date_entered >=  '2014-03-20 00:00:00' 
        AND emails.date_entered <=  '2014-06-30 00:00:00')
        GROUP BY assigned_user_id
    ) sub_emails
    ON t2.id = sub_emails.assigned_user_id
    LEFT JOIN 
    (
        SELECT assigned_user_id, COUNT( calls.id ) AS calls_count
        FROM calls 
        WHERE calls.assigned_user_id IN ( '1',  '2')
        AND (calls.date_entered >=  '2014-03-20 00:00:00' 
        AND calls.date_entered <=  '2014-06-30 00:00:00')
        GROUP BY assigned_user_id
    ) sub_calls
    ON t2.id = sub_calls.assigned_user_id
    LEFT JOIN 
    (
        SELECT assigned_user_id, COUNT( tasks.id ) AS tasks_count
        FROM tasks 
        WHERE tasks.assigned_user_id IN ( '1',  '2')
        AND (tasks.date_entered >=  '2014-03-20 00:00:00' 
        AND tasks.date_entered <=  '2014-06-30 00:00:00')
        GROUP BY assigned_user_id
    ) sub_tasks
    ON t2.id = sub_tasks.assigned_user_id
    WHERE t2.id IN ('1',  '2')
)t

注意,在子查询中检查用户id并不是绝对必要的,但应该会加快速度。

我看到您正在加入表并在之后进行筛选。例如:

SELECT t2.first_name, COUNT( DISTINCT emails.id ) AS te, COUNT( DISTINCT calls.id ) AS tc, COUNT( DISTINCT tasks.id ) AS tt
FROM  `users` AS t2
LEFT JOIN emails ON t2.id = emails.assigned_user_id
AND (

emails.date_entered >=  '2014-03-20 00:00:00'
AND emails.date_entered <=  '2014-06-30 00:00:00'
)
你应该这样做:

SELECT t2.first_name, COUNT( DISTINCT emails.id ) AS te, COUNT( DISTINCT calls.id ) AS tc, COUNT( DISTINCT tasks.id ) AS tt
FROM  `users` AS t2
LEFT JOIN 
(SELECT FIELDS_YOU_NEED 
 FROM `emails` 
 WHERE date_entered >=  '2014-03-20 00:00:00' AND date_entered <=  '2014-06-30 00:00:00'
 ) AS emails2 

ON t2.id = emails2.assigned_user_id

通过这种方式,您可以显著减少连接表所需的时间。

您可以给出表结构示例,其中包含数据,然后是其预期输出。还有表上的任何索引。这是错误的建议。MySQL实现了子查询并失去了使用索引的能力。谢谢!它可以工作,但当在te+tc+tt中时,如果任何值saytt为null,则结果为null。e、 g.如果30+10+0或null,则结果为null,但结果应显示40,您能否建议如何实现此目的?您可以使用IFNULLte、0+IFNULLtc、0+IFNULLtt、0