如何优化多个LEFT JOIN

尼古拉斯·汉弗莱

一些背景:

我们只有SELECT一个 MySQL 数据库的权限,需要计算每个用户在过去 1、2、...、45 天内花费了多少钱。查询是一个巨大的集合,LEFT JOIN我的任务是优化它。请注意,为了简化代码,我删除了大部分RoundLEFT JOIN注释。

编码:

SELECT m.username                                     AS 'Username', 

       # Actually we have 45 instead of 2 Round()
       Round(y2.spend, 2)                             AS '2', 
       Round(y1.spend, 2)                             AS '1' 
FROM   fund_m AS fm 
       LEFT JOIN member AS m 
              ON fm.user_id = m.id 
       LEFT JOIN employee AS e 
              ON m.account_manager = e.id

       # Again we have 45 instead of 2 LEFT JOIN following
       LEFT JOIN (SELECT fm.user_id                    AS id, 
                         Sum(fm.amount_changed) *- 1 AS 'spend' 
                  FROM   fund_m AS fm 
                  WHERE  fm.arrival_date = Subdate(CURRENT_DATE, 1) 
                         AND fm.type = 'impressions' 
                  GROUP  BY fm.user_id) AS y1 
              ON fm.user_id = y1.id 

       LEFT JOIN (SELECT fm.user_id                    AS id, 
                         Sum(fm.amount_changed) *- 1 AS 'spend' 
                  FROM   fund_m AS fm 
                  WHERE  fm.arrival_date = Subdate(CURRENT_DATE, 2) 
                         AND fm.type = 'impressions' 
                  GROUP  BY fm.user_id) AS y2 
              ON fm.user_id = y2.id 

WHERE  fm.arrival_date BETWEEN Subdate(CURRENT_DATE, 45) AND Subdate( 
                               CURRENT_DATE, 1) 
       AND fm.type = 'impressions' 
GROUP  BY m.username; 

表的结构fm如下:

每个用户都有一个user_idarrival_date列,所以代码检查是否到达日期是1,2,...,45天前CURRENT_DATE,然后Sumamount_charged基于这一点。该脚本还将总和显示为列。因此,每个 将有 45 列求和结果user_id

这是我使用 SQL 的第一天,经过一些研究,我得出了以下结论:

1) 它包含 45Round()LEFT JOIN,并且正在为 LOOP 或其他东西而尖叫。但是 AFAIK 我只能LOOP在存储过程中使用,而我不能这样做。接下来的想法是看看我是否可以创建一个临时表来保存1~45的序列。但是,我在 SO 上搜索了一段时间,无法确定真正有帮助的帖子。

2)是否可以在不使用的情况下生成 45 列LEFT JOIN因为我知道这LEFT JOIN需要大量资源,而 45(实际上是 47)LEFT JOIN似乎不是一个好主意(其中 45 是 self LEFT JOIN)。但我不知道如何优化它。

更新了一个想法,抱歉我不在工作区所以无法测试。只需阅读SELECT CASE WHEN ELSE END. 所以也许我可以CASE用来过滤日期(例如CASE WHEN现在和arrival_date1、2、...、45 天之间的差异)。但我仍然需要生成 45 列...

浅褐色的

更简化的版本。根据每个用户的合格日期和展示类型记录进行预聚合。由此,

select
      m.username AS 'Username',
      SUM( if( PQ.Days = 1, PQ.Spend, 0 )) as `1`,
      SUM( if( PQ.Days = 2, PQ.Spend, 0 )) as `2`,
      SUM( if( PQ.Days = 3, PQ.Spend, 0 )) as `3`,
      SUM( if( PQ.Days = 44, PQ.Spend, 0 )) as `44`,
      SUM( if( PQ.Days = 45, PQ.Spend, 0 )) as `45`,
   from
      ( select
              fm.user_id,
              datediff( current_date, fm.arrival_date ) as Days,
              Round( Sum(fm.amount_changed) * -1, 2 ) AS 'spend' 
           from
              fund_m AS fm 
           where
                  fm.arrival_date >= Date_Sub( Current_Date, interval 45 day )
              AND fm.type = 'impressions' 
           group by
              fm.user_id,
              datediff( current_date, fm.arrival_date )) PQ
         LEFT JOIN member AS m 
            ON PQ.user_id = m.id
            LEFT JOIN employee AS e
               ON m.account_manager = e.id
   group by
      m.username

如果您查看内部 PQ(预查询),我将应用所有 45 天(where 子句),并按用户和天数分组,我将 IF() 计算的天数追溯到(0-45 天)。在此查询结束时,您最多将拥有每人每天 1 条记录,因此外部查询联接可以从联接中获取其余数据。

这里更大的区别是它不会为每一行抛出 45 个日期比较,只是一个来确定从当前开始的 # 天。现在您有一个比预聚合小得多的有限集合,可以对天进行简单的检查以获得当天的总数。

您所拥有的组是按用户划分的,但您随后将加入员工表中的客户经理值。您是否打算根据帐户经理的姓名获取总数?如果不是,则甚至不需要加入员工表,除非您有一些其他字段,您没有按照此示例抓取。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在MySQL中优化多个JOIN

来自分类Dev

MySQL-如何改善使用多个LEFT JOIN的复杂查询

来自分类Dev

存在null时如何查询多个Left Join表

来自分类Dev

如何使用 LEFT JOIN 连接多个 mySQL 表?

来自分类Dev

Yii:优化LEFT OUTER JOIN到INNER JOIN

来自分类Dev

跨多个表优化 INNER JOIN

来自分类Dev

如何使用主查询中的LEFT JOIN和子查询中的INNER JOIN优化MySQL SELECT查询?

来自分类Dev

MySQL从多个表与LEFT JOIN多个

来自分类Dev

多个表中的多个 LEFT JOIN

来自分类Dev

是多个查询还是LEFT JOIN更快?

来自分类Dev

MySQL LEFT JOIN无法使用多个表

来自分类Dev

Nhibernate Left Join 中的多个条件

来自分类Dev

MySQL多个LEFT JOIN返回重复的行

来自分类Dev

在LEFT JOIN内的SQL JOIN

来自分类Dev

用join的结果数据大小,如何优化?

来自分类Dev

如何在Sequelize中使用ON子句中的多个谓词进行LEFT JOIN?

来自分类Dev

如何在R中left_join并重复将值连接到多个变量?

来自分类Dev

如何使用ON子句中的多个谓词在Sequelize中进行LEFT JOIN?

来自分类Dev

如何根据行名合并/left_join多个数据框

来自分类Dev

优化SQL JOIN调用

来自分类Dev

Oracle JOIN 输出优化

来自分类Dev

PostgreSQL:具有多个条件的多个LEFT JOIN

来自分类Dev

如何编写RIGHT OUTER JOIN和LEFT OUTER JOIN的组合

来自分类Dev

如何在 LEFT JOIN 中嵌套 INNER JOIN

来自分类Dev

如何使用SQL LEFT JOIN查询

来自分类Dev

如何使用SQL LEFT JOIN查询

来自分类Dev

如何从LEFT JOIN MySQL表调用结果

来自分类Dev

如何为 LEFT JOIN 设置条件?

来自分类Dev

如何获得 COUNT 的 LEFT JOIN 数据