2015-01-05 27 views
1

我有一个查询,它适用于1000条记录或更少,但现在我需要优化它的50,000条记录,当我运行它时,它只是停顿...更好的优化SELECT SQL查询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

附加'EXPLAIN'查询规划输出 – Antoniossss

+1

我通常发现,MySQL的连接优化比相关子好,虽然我听说它在最近的版本更好。 – Barmar

+0

“or b2.effective_date is null”的删除对结果有什么影响!?!? – Strawberry

回答

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 
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