繁体   English   中英

如何通过多个联接加快执行SQL查询的速度?

[英]How to speed up the execution of sql query with multiple joins?

我正在使用MySql数据库。 我需要将多个(超过10个)表中的信息合并到一个表中。 为此,我遵循一种典型的加入方式。

Select * from 
table_1 
Join table_2
on(table_1.id = table_2.id)
Join table_3
on(table_1.id = table_3.id)

它可以工作,但是在执行期间我受了很多苦。 还有其他优化我的代码的好方法吗? 以下是我的代码示例:

SELECT
distinct 
u.Id, 
oc.dt,
Daily_Number_Outgoing_Calls,     
Daily_Number_Incoming_Calls,    
Daily_duration_Outgoing_Calls

FROM
creditfix.users u

JOIN

#1 Daily_No_Out_Calls
    (
        SELECT
        cl.uId,SUBSTRING(DATE,1,10) as dt,
        count(1) as Daily_Number_Outgoing_Calls

        From creditfix.call_logs as cl
            WHERE
                cl.`type`=2 #out going calls only
        GROUP by cl.uId,dt
    ) oc
    ON (u.Id=oc.Uid)

#2 Daily_No_In_Calls
    JOIN
    (
        SELECT
        cl.uId, SUBSTRING(DATE,1,10) as dt,
        count(1) as Daily_Number_Incoming_Calls
        From creditfix.call_logs as cl
        WHERE
            cl.`type`=1 #incoming calls only
        GROUP by cl.uId,dt
    ) ic
    ON (u.Id=ic.Uid)

#3 Daily_duration_Out_Calls
     JOIN
    (
        SELECT
        cl.uId,SUBSTRING(DATE,1,10) as dt, 
        (sum(duration)) as Daily_duration_Outgoing_Calls
        From creditfix.call_logs as cl
        WHERE
            cl.`type`=2 #out going calls only
        GROUP by cl.uId,dt
    ) od
    ON (u.Id=od.uid)
    # It goes on like this...

看起来您不需要为每个列使用单独的子查询,您应该能够在单个子查询中进行操作。

我也认为您在主查询中不需要DISTINCT

SELECT 
    u.Id, 
    cl.dt,
    cl.Daily_Number_Outgoing_Calls,     
    cl.Daily_Number_Incoming_Calls,    
    cl.Daily_duration_Outgoing_Calls,   
    cl.Daily_duration_Incoming_Calls #.... for keep on adding like this

FROM creditfix.users u
JOIN (
    SELECT uId, SUBSTRING(DATE, 1, 10) AS dt,
        SUM(`type`=2) AS Daily_Number_Outgoing_Calls,
        SUM(`type`=1) AS Daily_Number_Incoming_Calls,
        SUM(IF(`type`=2, duration, 0)) AS Daily_duration_Outgoing_Calls,
        SUM(IF(`type`=1, duration, 0)) AS Daily_duration_Incoming_Calls
    FROM creditfix.call_logs as cl
    GROUP BY uId, dt) AS cl
ON u.Id = cl.uId

请参阅多个查询相同的表,但在mysql的不同列中,以获取子查询中用于获取所有计数的逻辑。

如评论中所述,这些不是简单的联接,它们是子查询联接,这使得优化更加困难。 您必须优化每个子查询,或者找到一种不需要子查询的方法。

由于您要获取给定日期的每个用户的呼叫日志信息并进行键入,因此可以通过简单的加入和分组方式来完成。 无需子查询。

select
    ???
from
    creditfix.users u
join
    creditfix.call_logs as cl on u.id = cl.uid
where
    substring(date,1,10)=???
group by
    cl.uid, cl.type;

因此,要复制您要查找的内容,通话次数及其总持续时间...

select
    u.id, cl.type, count(cl.id) as num_calls, sum(cl.duration) as duration
from
    creditfix.users u
join
    creditfix.call_logs as cl on u.id = cl.uid
where
    substring(date,1,10)='2017-03-18'
group by
    cl.uid, cl.type;

你会得到这样的东西。

+----+------+-----------+---------------+
| id | type | num_calls | call_duration |
+----+------+-----------+---------------+
|  1 |    1 |         3 |            20 |
|  1 |    3 |         1 |            10 |
|  1 |    5 |         2 |             4 |
|  2 |    5 |         1 |             4 |
+----+------+-----------+---------------+

这样就失去了为每个单独的列命名的能力,但这就是接收查询可以处理的任何事情。 或者可以使用单个子查询来处理。

types可以用case来命名...

case cl.type
    when 1 then 'outgoing'
    when 2 then 'incoming'
    when 3 then ...
    else cl.type
end as type

...但是这需要对查询中的幻数进行硬编码。 您最好制作一个表来存储有关类型的信息并加入其中。


子查询本身在此处存在潜在的性能问题: substring(date,1,10) = '2017-03-08' 如果未索引date ,则查询将必须进行全表扫描。

使用date作为字符串会带来性能问题。 数据库必须在每一行上执行字符串操作,尽管MySQL可能足够聪明以使用索引。 而使用datetime类型则是一个简单的数字比较,并且将使用索引。 它也更小,8字节。

它使您无需转换即可使用日期和时间函数 SUBSTRING(DATE,1,10)可以替换为更快更安全的date(date)

命名列date也是一个坏主意,它是MySQL中的函数名称,可能会引起问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM