Oracle查询运行速度太慢(大约需要5小时)

时间:2014-02-26 19:01:23

标签: sql oracle

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

3 个答案:

答案 0 :(得分: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')
        )

看看你是否可以某种方式将这种存在的逻辑改为具有更好性能的东西。解释计划是必须的!

答案 1 :(得分:2)

基于我正在使用的DW中的类似查询,我将在这里进行半盲猜测。 Oracle的优化器容易被谓词混淆,例如:

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

原因是甲骨文大大高估了选择性。 像别人说的那样检查解释计划。如果您发现表dwprod.fct_claim的估计基数似乎太低,请尝试展开案例陈述。

例如,而不是:

  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中似乎不是问题,但我还没来得及调查原因。

答案 2 :(得分:-1)

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

此交叉连接实际上是内连接。我不能说Oracle是否会对此进行优化,但没有理由不让它的工作变得更容易:

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