2014-02-26 122 views
0
SELECT t1.member_id , 
    SUM(t1.paid_amt) AS paid_amt 
FROM 
    (SELECT DISTINCT fm.member_id, 
    fc.claim_skey_no, 
    fc.claim_id, 
    fc.claim_line_no , 
    CASE 
     WHEN fc.claim_type_cd = 'RX' 
     THEN NVL(fc.rx_paid_amt,0) -- For RX claims use rx_paid_amt as paid amount 
     ELSE NVL(fc.approved_amt,0) 
    END AS paid_amt -- For all other claims use approved_amt 
    , 
    CASE 
     WHEN fc.claim_type_cd = 'RX' 
     THEN fc.submit_dt --For RX claims use submit_dt as paid date 
     ELSE NVL(fc.paid_dt,NVL(fc.edi_eob_dt,NVL(fc.eob_run_dt,fc.outsource_vndr_paid_dt))) 
    END AS paid_dt --For all other claims use paid_dt 
    FROM dwprod.fct_claim fc , 
    dwprod.fct_member fm 
    WHERE fc.mbr_skey_no = fm.member_skey_no 
    -- The service_from_dt on the claim must be between the reimbursement time period. 
    AND fc.service_from_dt BETWEEN '31-MAY-2013' AND '30-Jun-2014' 
    -- The follwong 2 conditions make sure that the calims selected are final-status (unadjusted) 
    -- For non-RX claims, the adjust_type_cd must be Null and the dw_backout_tag must be Null or 'N' 
    -- For RX claims only the dw_backout_tag must be Null or 'N', the adjust_type_cd is ignored 
    AND 
    CASE 
     WHEN fc.claim_type_cd = 'RX' 
     THEN 1 
     WHEN fc.claim_type_cd <> 'RX' 
     AND fc.adjust_type_cd IS NULL 
     THEN 1 
     ELSE 0 
    END       = 1 
    AND NVL(fc.dw_backout_tag,'N') = 'N' 
    -- The claim must be in an 'Approved' status, indicated by a status_type_cd = 'A' 
    AND fc.status_type_cd = 'A' 
    -- QNXT claims must be in a 'PAID' status 
    -- Non QNXT claims in the warehouse are assumed to be paid - There are no pended RX claims. 
    AND 
    CASE 
     WHEN fc.dw_source_cd <> 'QNXT' 
     THEN 1 
     WHEN fc.dw_source_cd = 'QNXT' 
     AND fc.last_status_nm = 'PAID' 
     THEN 1 
     ELSE 0 
    END = 1 
    -- Dental claims are excluded 
    AND fc.dw_source_cd <> 'DBP' 
    -- Excludes any Medicare Non-RCI claims 
    AND 
    CASE 
     WHEN NVL(fc.program_nm,'OTHER') = 'MEDICAID' 
     AND NVL(fc.enroll_ratecode,'RCI') IN ('RCII','RCV','RCVII') 
     THEN 0 
     ELSE 1 
    END = 0 
    -- It Fits! claims are excluded 
    AND NVL(fc.expense_cat_nm,'Other') <> 'FITNESS' 
    AND NVL(fc.proc1_skey_no,12345) NOT IN (21586,21588,21589) 
    -- 
    AND 
    CASE 
     WHEN NVL(fc.program_nm,'OTHER') = 'MEDICAID' 
     AND NVL(fc.enroll_ratecode,'RCI') IN ('RCII','RCV','RCVII') 
     THEN 1 
     WHEN EXISTS 
     (SELECT 1 
     FROM dwprod.fct_member_enroll me 
     WHERE fm.member_skey_no = me.mbr_skey_no 
     AND fc.service_from_dt BETWEEN me.segment_effect_dt AND me.segment_term_dt 
     AND me.program_nm  = 'MEDICAID' 
     AND me.enroll_ratecode IN ('RCII','RCV','RCVII') 
     ) 
     THEN 1 
     ELSE 0 
    END = 1 
) t1 
    --Where t1.paid_dt < '31-JAN-2014' 
GROUP BY t1.member_id 
HAVING SUM(t1.paid_amt) > 175000 
+0

我試過用這個(FROM dwprod.fct_claim fc,INNER JOIN dwprod.fct_member fm ON fc.mbr_skey_no = fm.member_skey_no)仍然需要很長時間。 – user3357343

+1

您是否檢查了EXPLAIN PLAN?如果不是,爲什麼不呢? –

+0

儘管對您的問題沒有多大意義,但'AND FC.SERVICE_FROM_DT BETWEEN '31 -MAY-2013'和'30 -JUN-2014''應該是AND AND FC.SERVICE_FROM_DT之間的TO_DATE('31 -MAY-2013' ,'DD-MON-YYYY')和TO_DATE('30 -JUN-2014','DD-MON-YYYY')' – SriniV

回答

5

運行解釋計劃以查看導致放緩的原因。從我的頭頂,這是什麼「殺」你:

WHEN EXISTS 
     (SELECT 1 
     FROM dwprod.fct_member_enroll me 
     WHERE fm.member_skey_no = me.mbr_skey_no 
     AND fc.service_from_dt BETWEEN me.segment_effect_dt AND me.segment_term_dt 
     AND me.program_nm  = 'MEDICAID' 
     AND me.enroll_ratecode IN ('RCII','RCV','RCVII') 
     ) 

看看你是否能以某種方式改變這種邏輯存在的東西具有更好的性能。解釋計劃是必須的!

+2

我同意一個解釋計劃會大大幫助解決這個性能問題。如果沒有這些,我會猜想問題的另一部分是謂詞太複雜,甲骨文無法正確估計。這導致基數估計較差,ROWS = 1,其中有數百或數十億行返回。然後導致NESTED LOOP而不是HASH JOIN。有了這樣複雜的謂詞,可能不會有一個好方法將優化器推向正確的方向。這可能需要像'/ * + use_hash(fc fm)full(fc)full(fm)* /'這樣的提示。 –

+0

我同意!在解釋計劃之後,您可以看到優化器的功能,然後使用Oracle提示來提高性能。我看到優化器做了很不合理的決定(完全是嵌套循環而不是散列連接),並且一個簡單的提示已經將查詢從大約30分鐘改善到了大約1分鐘... – Koshera

-1
FROM dwprod.fct_claim fc , 
    dwprod.fct_member fm 
WHERE fc.mbr_skey_no = fm.member_skey_no 

這個交叉連接實際上是一個內部連接。我不能說甲骨文是否會優化這一點,但我們沒有理由不使自己的工作更輕鬆:

FROM dwprod.fct_claim fc , 
    INNER JOIN dwprod.fct_member fm 
    ON fc.mbr_skey_no = fm.member_skey_no 
+0

我更喜歡ANSI語法,並且相信它會提高性能從長遠來看,通過使查詢更易於理解和調試。但對於這個具體的陳述,我認真地懷疑這將有助於表現。無論如何,Oracle將大多數ANSI語法轉換爲舊式語法。 –

+0

我更喜歡ANSI,但不是在12c中,因爲使用這種方式有一個開放的錯誤。由於12c在外連接方面有一些增強,與舊版本相比,SQL的處理方式不同。看這裏http://stackoverflow.com/questions/19686262/query-featuring-outer-joins-behaves-differently-in-oracle-12c – SriniV

2

我會做一個半盲猜這裏,基於DW I」類似的查詢與...合作。 Oracle的優化被容易被混淆的謂詞如:

where (case when ... then ... else ... end) = 1; 

的原因是,甲骨文在嚴重估計選擇性。 像其他人說的那樣查看解釋計劃。如果您發現表dwprod.fct_claim的估計基數看起來太低,請嘗試展開case語句。

例如,而不是:

AND CASE WHEN fc.dw_source_cd <> 'QNXT' THEN 1 
      WHEN fc.dw_source_cd = 'QNXT' AND fc.last_status_nm = 'PAID' THEN 1 
                      ELSE 0 
     END = 1 

寫:

and ( fc.dw_source_cd <> 'QNXT' 
    or (fc.dw_source_cd = 'QNXT' and fc.last_status_nm = 'PAID') 
    ) 

最後說明。這在版本11中似乎不太成問題,但我還沒有時間去調查原因。