2013-12-18 19 views
0

我在一組SQL中存在性能問題,無法實時生成當前月份的報表。Oracle SQL月度對賬單生成

客戶將使用來自在線系統的點數購買一些商品,並且應該生成包含「open_balance」,「point_earned」,「point_used」,「current_balance」的語句。

下面顯示了縮短模式:

//~200k records 
customer: {account_id:string, create_date:timestamp, bill_day:int} //totally 14 fields 

//~250k records per month, kept for 6 month 
history_point: {point_id:long, account_id:string, point_date:timestamp, point:int} //totally 9 fields 

//each customer have maximum of 12 past statements kept 
history_statement: {account_id:string, open_date:date, close_date:date, open_balance:int, point_earned:int, point_used:int, close_balance:int} //totally 9 fields 

在每個賬單日,視圖會自動創建一個新的一個月的語句。 即如果bill_day爲15,那麼2013年12月16日或之後完成的交易00:00:00應該屬於2013年12月16日的新帳單週期00:00:00 - 2014年1月15日23:59:59

I試圖

  1. 計算每個帳戶的最後收市下面所描述的方法,(在物化視圖,使其僅更新後有插入history_statement新客戶或過去的一個月中陳述)
  2. 生成一個記錄每個客戶每個月我需要計算(也在物化視圖中)
  3. 篩分點rec ord僅用於計算日期內的點記錄(這隻需要〜0.1s)
  4. 加入2與3以獲得積分並用於每個客戶每月
  5. 加入4與4日期少於打開日期到期末餘額 6a。從開始日期小於1個月大的地方開始選擇5作爲當前餘額(這些還沒有關閉,並且該點反映了每個客戶擁有的點數) 6b。所有的陳述都是通過history_statement和union聯合獲得的5

在開發服務器上,平均響應時間(200K客戶,當月1.5M的交易)測試服務器的資源可能會被共享,平均響應時間(20萬客戶,每月約8萬個交易約20萬次)爲10-15秒。

有沒有人有更好的方法來編寫查詢或加快查詢的一些想法?

相關SQL:

2:IV_STCLOSE_2_1_T(物化視圖)

3:IV_STCLOSE_2_2_T(〜0.15秒)

SELECT ACCOUNT_ID, POINT_DATE, POINT 
FROM history_point 
WHERE point_date >= ( 
    SELECT MIN(open_date) 
    FROM IV_STCLOSE_2_1_t 
) 

4:IV_STCLOSE_3_T(〜1.5秒)

SELECT p0.account_id, p0.open_date, p0.close_date, COALESCE(SUM(DECODE(SIGN(p.point),-1,p.point)),0) AS point_used, COALESCE(SUM(DECODE(SIGN(p.point),1,p.point)),0) AS point_earned 
FROM iv_stclose_2_1_t p0 
LEFT JOIN iv_stclose_2_2_t p 
ON p.account_id = p0.account_id 
AND p.point_date >= p0.open_date 
AND p.point_date < p0.close_date + INTERVAL '1' DAY 
GROUP BY p0.account_id, p0.open_date, p0.close_date 

5:IV_STCLOSE_4_T(〜3s)

WITH t AS (SELECT * FROM IV_STCLOSE_3_T) 
SELECT t1.account_id AS STAT_ACCOUNT_ID, t1.open_date, t1.close_date, t1.open_balance, t1.point_earned AS point_earn, t1.point_used , t1.open_balance + t1.point_earned + t1.point_used AS close_balance 
FROM (
    SELECT v1.account_id, v1.open_date, v1.close_date, v1.point_earned, v1.point_used, COALESCE(sum(v2.point_used + v2.point_earned),0) AS OPEN_BALANCE 
    FROM t v1 
    LEFT JOIN t v2 
    ON v1.account_id = v2.account_id 
    AND v1.OPEN_DATE > v2.OPEN_DATE 
    GROUP BY v1.account_id, v1.open_date, v1.close_date, v1.point_earned, v1.point_used 
) t1 
+1

一些備註:1)它可能會幫助,看看實際的查詢中使用2)你應該運行'EXPLAIN PLAN「,並顯示該命令的結果 – fvu

+0

@fvu相關策略的SQL位於該帖子的底部。 – kftse

回答

0

它原來是在IV_STCLOSE_4_T

WITH t AS (SELECT * FROM IV_STCLOSE_3_T) 

是有問題的。

起初以爲WITH t AS將作爲IV_STCLOSE_3_T只計算一次速度更快,但它顯然是被迫物化整個IV_STCLOSE_3_T,產生超過20萬條記錄,儘管我只在任何時候需要他們至多12從單一的客戶。

上述說法取出並適當索引ACCOUNT_ID,費用從超過50萬減少到不足500