Oracle DB

时间:2016-05-08 04:48:41

标签: sql oracle performance query-optimization

我的查询运行了近2个小时而没有产生任何结果。我已经采取了执行计划,它看起来像下面。 enter image description here

代码

此代码基本上执行数据透视操作:

SELECT y.COMPANYNAME as OIPACOMPANYNAME, 
       z.POLICYNUMBER as OIPAPOLICYNUMBER,
       x.STATUSCODE as OIPASTATUSCODE,
       MAX(CASE 
       WHEN w.FIELDTYPECODE='01' AND w.FIELDNAME='PolicyEffDate' THEN w.DATEVALUE
       ELSE NULL
       END ) as OIPAPOLICYEFFDATE,
       x.ISSUESTATECODE as OIPAISSUESTATECODE,
     NULL as OIPACURRENTSTATECODE,
       MAX(CASE 
       WHEN w.FIELDTYPECODE='01' AND w.FIELDNAME='PolicyEndDate' THEN w.DATEVALUE
       ELSE NULL
       END ) as OIPAPOLICYENDDATE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='03' AND w.FIELDNAME='IssueAge' THEN w.INTVALUE
       ELSE NULL
       END) as OIPAISSUEAGE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='03' AND w.FIELDNAME='PolicyYear' THEN w.INTVALUE
       ELSE NULL
       END) as OIPAPOLICYYEAR,
       V.PLANNAME AS OIPAPLANNAME,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='PolicyUniqueIdentifier' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAPOLUPI,
     NULL as OIPAPLANMODALFACTOR,  
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='Participating' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAPARTICIPATING,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='Participating' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAREINSURANCETYPE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='BaseFaceAmount' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPABASEFACEAMOUNT,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='QualType' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAQUALTYPE,
     NULL as OIPATAXQUALSALESMARKET, --- field record not found hence set as null 
     MAX(CASE 
       WHEN w.FIELDTYPECODE='01' AND w.FIELDNAME='BillToDate' THEN w.DATEVALUE
       ELSE NULL
       END) as OIPABILLTODATE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='01' AND w.FIELDNAME='PaidToDate' THEN w.DATEVALUE
       ELSE NULL
       END) as OIPAPAIDTODATE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='PaymentMode' THEN w.TEXTVALUE
       ELSE NULL
      END ) as OIPAPAYMENTMODE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='PaymentMethod' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAPAYMENTMETHOD,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='03' AND w.FIELDNAME='BillingLeadDays' THEN w.INTVALUE
       ELSE NULL
       END) as "OIPABILLING LEAD DAYS",
     MAX(CASE 
       WHEN w.FIELDTYPECODE='03' AND w.FIELDNAME='BankDraftDay' THEN w.INTVALUE
       ELSE NULL
       END) as OIPABANKDRAFTDAY,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='EFTDraftCode' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAEFTDRAFTCODE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='CurrentModalPremiumAmt' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPACURRENTMODALPREMIUMAMT,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='CurrentAnnualPremiumAmt' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPACURRENTANNUALPREMIUMAMT,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='PolicyModalPremiumAdjustment' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPAPOLICYMODALPREMIUMADJ,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='PolicyFee' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPAPOLICYFEE,
     NULL as OIPALOANPRINCIPAL,
     NULL as OIPAOUTSTANDINGLOAN,
     NULL as OIPALOANINTERESTDUE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='LoanInterestRate' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPALOANINTERESTRATE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='LoanInterestType' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPALOANINTERESTTYPE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='APLIndicator' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPAAPLINDICATOR,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='03' AND w.FIELDNAME='LoanBankDraftDay' THEN w.INTVALUE
       ELSE NULL
       END) as OIPALOANBANKDRAFTDAY,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='LoanPaymentMethod' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPALOANPAYMENTMETHOD,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='LoanPaymentMode' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPALOANPAYMENTMODE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='LoanModalPaymentAmount' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPALOANMODALPAYMENTAMOUNT,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='03' AND w.FIELDNAME='LoanBillingLeadDays' THEN w.INTVALUE
       ELSE NULL
       END) as OIPALOANBILLINGLEADDAYS,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='01' AND w.FIELDNAME='LoanBillingDate' THEN w.DATEVALUE
       ELSE NULL
       END) as OIPALOANBILLINGDATE,
     NULL as OIPAPITCASHVALUE,
     NULL as OIPAPITCASHSURRVALUE,
     NULL as OIPANXTMODVARCASHVALUE,
     NULL as OIPAPITDIVONDEP,
     NULL as OIPAPITINTONDEP,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='DividendOptionPrimary' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPADIVIDENDOPTIONPRIMARY,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='DividendOptionSecondary' THEN w.TEXTVALUE
       ELSE NULL
       END) as OIPADIVIDENDOPTIONSECONDARY,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='DividendToApplyToCash' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPADIVIDENDTOAPPLYTOCASH,
     NULL as OIPADIVIDENDTOAPPLYTOACCUDIV,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='DividendToApplyToLoan' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPADIVIDENDTOAPPLYTOLOAN,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='DividendToApplyToOYT' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPADIVIDENDTOAPPLYTOOYT,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='DividendToApplyToPremium' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPADIVIDENDTOAPPLYTOPREMIUM,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='DividendToApplyToPUA' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPADIVIDENDTOAPPLYTOPUA,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='DividendInterestRate' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPADIVIDENDINTERESTRATE,
     MAX(CASE 
       WHEN w.FIELDTYPECODE='01' AND w.FIELDNAME='DividendDeclaredDate' THEN w.DATEVALUE
       ELSE NULL
       END) as OIPADIVIDENDDECLAREDDATE,
     NULL as OIPAPUA,
     NULL as OIPAPUAPURCHASEDLASTANN,----- field record not found hence set as null 
     NULL as OIPAOYT,--field record not found hence set as null
     NULL as OIPAEICTOAPPLYTOOYT,--- field record not found hence set as null 
     MAX(CASE 
       WHEN w.FIELDTYPECODE='04' AND w.FIELDNAME='NetCostBasis' THEN w.FLOATVALUE
       ELSE NULL
       END) as OIPANETCOSTBASIS,


     a.SEGMENTGUID as "OIPASEGMENTGUID",
     MAX(CASE 
       WHEN b.FIELDTYPECODE='02' AND b.FIELDNAME='SegmentFormerSystemPlanCode' THEN b.TEXTVALUE
       ELSE NULL
       END ) as "OIPASEGMENTFORMERSYSTEMPLAN",
     c.SEGMENTNAME as "OIPASEGMENTNAME",
     MAX(CASE 
       WHEN b.FIELDTYPECODE='02' AND b.FIELDNAME='SegmentStatusCode' THEN b.TEXTVALUE
       ELSE NULL
       END ) as "OIPASEGMENTSTATUSCODE",
     MAX(CASE 
       WHEN b.FIELDTYPECODE='01' AND b.FIELDNAME='SegmentIssueDate' THEN b.DATEVALUE
       ELSE NULL
       END ) as "OIPASEGMENTISSUEDATE",
     MAX(CASE 
       WHEN b.FIELDTYPECODE='01' AND b.FIELDNAME='SegmentEndDate' THEN b.DATEVALUE
       ELSE NULL
       END ) as "OIPASEGMENTENDDATE",
     MAX(CASE 
       WHEN b.FIELDTYPECODE='01' AND b.FIELDNAME='SegmentTerminationDate' THEN b.DATEVALUE
       ELSE NULL
       END ) as OIPASEGMENTTERMINATIONDATE,
     MAX(CASE 
       WHEN b.FIELDTYPECODE='03' AND b.FIELDNAME='SegmentIssueAge' THEN b.INTVALUE
       ELSE NULL
       END ) as OIPASEGMENTISSUEAGE,
     MAX(CASE 
       WHEN b.FIELDTYPECODE='03' AND b.FIELDNAME='BaseIssueAge' THEN b.INTVALUE
       ELSE NULL
       END ) as OIPABASEISSUEAGE  
     FROM ASPOLICY x LEFT JOIN ASCOMPANY y ON (x.COMPANYGUID=y.COMPANYGUID)
     INNER JOIN AUDIT_EXT_TEMP_BULK Z ON (z.COMPANYGUID=y.COMPANYGUID and x.POLICYGUID=Z.POLICYGUID )
     LEFT JOIN ASPOLICYFIELD w ON (W.POLICYGUID=z.POLICYGUID)
     LEFT JOIN ASPLAN v ON (v.PLANGUID=x.PLANGUID AND v.COMPANYGUID=z.COMPANYGUID) -- Plan Information
     LEFT JOIN ASSEGMENT a ON (x.POLICYGUID=a.POLICYGUID)  -- Segment 
     LEFT JOIN ASSEGMENTFIELD b ON (b.SEGMENTGUID=a.SEGMENTGUID) -- Segment 
     LEFT JOIN ASSEGMENTNAME c ON (c.SEGMENTNAMEGUID=a.SEGMENTNAMEGUID) 
     GROUP BY y.COMPANYNAME,

             z.POLICYNUMBER,

             x.STATUSCODE,

             x.ISSUESTATECODE,

             v.PLANNAME,

             a.SEGMENTGUID,

             c.SEGMENTNAME;

为了便于阅读,以下是声明的尾部:

FROM ASPOLICY x LEFT JOIN ASCOMPANY y ON (x.COMPANYGUID=y.COMPANYGUID)
INNER JOIN AUDIT_EXT_TEMP_BULK Z ON (z.COMPANYGUID=y.COMPANYGUID 
                                      and x.POLICYGUID=Z.POLICYGUID )
LEFT JOIN ASPOLICYFIELD w ON (W.POLICYGUID=z.POLICYGUID)
LEFT JOIN ASPLAN v ON (v.PLANGUID=x.PLANGUID 
                       AND v.COMPANYGUID=z.COMPANYGUID) -- Plan Information
LEFT JOIN ASSEGMENT a ON (x.POLICYGUID=a.POLICYGUID)  -- Segment 
LEFT JOIN ASSEGMENTFIELD b ON (b.SEGMENTGUID=a.SEGMENTGUID) -- Segment 
LEFT JOIN ASSEGMENTNAME c ON (c.SEGMENTNAMEGUID=a.SEGMENTNAMEGUID) 
GROUP BY y.COMPANYNAME,
         z.POLICYNUMBER,
         x.STATUSCODE,
         x.ISSUESTATECODE,
         v.PLANNAME,
         a.SEGMENTGUID,
         c.SEGMENTNAME;

这些表具有以下索引,其中箭头的左侧表示表,右侧表示具有索引的列。请注意:在运行查询之前,我已通过运行dbms_stats.gather_table_stats('schema','table name');

更新了表中的统计信息
AUDIT_EXT_TEMP_BULK-->COMPANYGUID,POLICYGUID);

ASPLAN-->PLANGUID

ASPOLICY-->COMPANYGUID

ASCOMPANY-->COMPANYGUID

ASPOLICYFIELD-->POLICYGUID

ASSEGMENT-->POLICYGUID

ASSEGMENTFIELD-->SEGMENTGUID

ASSEGMENTNAME-->SEGMENTNAMEGUID

1 个答案:

答案 0 :(得分:3)

  

“此代码基本上执行数据透视操作”

所以它实际上做的是尝试从an Entity-Attribute-Value model创建一个连贯的结果集。众所周知,这些很难调整。 EAV适合某些用例,例如分析,但是从一组雾化列重新构造一行是非常昂贵的。它们也很难查询(正如您现在所知道的那样!)并且也容易出错,因为重构是一个手动过程 - 这可能不是您需要为OIPAREINSURANCETYPE返回的内容:

 MAX(CASE 
   WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='Participating' THEN w.TEXTVALUE
   ELSE NULL
   END) as OIPAPARTICIPATING,
 MAX(CASE 
   WHEN w.FIELDTYPECODE='02' AND w.FIELDNAME='Participating' THEN w.TEXTVALUE
   ELSE NULL
   END) as OIPAREINSURANCETYPE,

这表明EAV在大多数情况下都不适合使用。模式仍然是固定的,它只是硬编码为读取而不是写入。

当然,对于我们这些必须查询“模型”的人来说,EAV并不难:它还使数据库无法理解数据的存储方式,从而产生糟糕的执行计划。

我承认我印象深刻:我不记得上次在解释计划的G栏中看到Rows时。也就是说,您的解释计划显示您的查询正在与 ~923,000,000,000行搏斗,其中GROUP BY将归结为 ~7,879,000,000行

那么,考虑到您返回了多少数据,您认为应该花多长时间?

也许最后一个数字让你感到惊讶。毫无疑问,你期待7789行(每个政策一行)。相反,你有一个可怕的笛卡尔积。所有这些额外的行来自哪里?

其中一个问题是AUDIT_EXT_TEMP_BULK上的联接:每个策略添加超过800行,因为该表上没有过滤器。这是一种检索策略编号的昂贵方法,可能对每个策略都是固定的。如果没有更合理的方法来获取这个值(比如ASPOLICY表上的一列),用内联视图替换该表应该会减少相当多的数字:

INNER JOIN (select distinct COMPANYGUID, POLICYGUID, POLICYNUMBER 
         from  AUDIT_EXT_TEMP_BULK Z )
 ON (z.COMPANYGUID=y.COMPANYGUID and x.POLICYGUID=Z.POLICYGUID )

另一件事是GROUP BY:您实际上只需聚合这些列:

y.COMPANYNAME as OIPACOMPANYNAME, 
z.POLICYNUMBER as OIPAPOLICYNUMBER,
x.STATUSCODE as OIPASTATUSCODE

删除其他列可能会大大改善解释计划。