针对50,000多条记录更好地优化了SELECT SQL查询

时间:2015-01-05 17:12:52

标签: mysql sql

我有一个查询适用于1000条或更少的记录,但现在我需要优化它以获得50,000条以上的记录,当我在它上面运行它只是停止...

这是我的代码:

SELECT  
b1.account_num,b1.effective_date as ed1,b1.amount as am1,
b2.effective_date as ed2,b2.amount as am2
FROM bill b1
left join bill b2 on (b1.account_num=b2.account_num)
where b1.effective_date = (select max(effective_date) from bill where account_num = b1.account_num)
and (b2.effective_date = (select max(effective_date) from bill where account_num = b1.account_num and effective_date < (select max(effective_date) from bill where account_num = b1.account_num)) or b2.effective_date is null)
ORDER BY b1.effective_date DESC

我的目标是从一张包含许多记录的表格中获取最新的两个生效日期和金额。

2 个答案:

答案 0 :(得分:1)

Here is a working answer from your SQL-Fiddle baseline

首先,内部preQuery获取每个帐户的最大日期。然后将其加入到每个帐户的帐单表中,并且生效日期小于已检测到的最大值。

然后加入各自的账单以获取金额。

select
      FB1.account_num,
      FB1.effective_date as ed1,
      FB1.amount as am1,
      FB2.effective_date as ed2,
      FB2.amount as am2
   from
      ( select
              pq1.account_num,
              pq1.latestBill,
              max( b2.effective_date ) as secondLastBill
           from
              ( SELECT  
                      b1.account_num,
                      max( b1.effective_date ) latestBill
                   from
                      bill b1
                   group by
                      b1.account_num ) pq1
                 LEFT JOIN bill b2
                    on pq1.account_num = b2.account_num
                   AND b2.effective_date < pq1.latestBill 
            group by
               pq1.account_num ) Final
         JOIN Bill FB1
            on Final.Account_Num = FB1.Account_Num
            AND Final.LatestBill = FB1.Effective_Date

         LEFT JOIN Bill FB2
            on Final.Account_Num = FB2.Account_Num
            AND Final.secondLastBill = FB2.Effective_Date
   ORDER BY
      Final.latestBill DESC

答案 1 :(得分:0)

在mysql中,像row_number这样的窗口分析函数不存在,所以我们可以使用变量来模拟相同的。

好处是,用这种方法只扫描一次表。

row_number分配给每个分区,根据(帐号,生效日期)划分,每个分区只选择2行。

select  account_num,
        max(case when row_number =1 then effective_date end) as ed1,
        max(case when row_number =1 then amount end) as am1,
        max(case when row_number =2 then effective_date end) as ed2,
        max(case when row_number =2 then amount end )as am2

from (
select account_num, effective_date, amount,
      @num := if(@prevacct= account_num , @num + 1, 1) as row_number,
      @prevacct := account_num as dummy
from bill, (select @num:=0, @prevacct := '' ) as var
order by account_num , effective_date desc
 )T
where row_number <=2
group by account_num