2014-02-26 77 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中似乎不太成问题,但我还没有时间去调查原因。