2015-01-05 24 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