简体   繁体   English

Oracle DB中的查询的Oracle性能调优

[英]Oracle Performance tuning of a query in Oracle DB

I have a query which runs for almost 2 hours without producing any result. 我有一个查询,运行了近2个小时,没有产生任何结果。 I have taken the execution plan and it looks like below . 我已经采取了执行计划,它看起来像下面。 在此输入图像描述

Code

This code basically does pivot operation: 此代码基本上执行pivot操作:

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;

Here is the tail of the statement exposed for readability: 以下是为了便于阅读而公开的声明的尾部:

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;

The tables have the following indexes, where left side of the arrow represents the table and right side represents the column which have index on it. 这些表具有以下索引,其中箭头的左侧表示表,右侧表示具有索引的列。 Please note: before running the query I had updated stats on the tables by running dbms_stats.gather_table_stats('schema','table name'); 请注意:在运行查询之前,我通过运行dbms_stats.gather_table_stats('schema','table name');更新了表的统计信息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

"This code basically does pivot operation" “这段代码基本上做了枢轴操作”

So what it actually does is attempt to create a coherent result set from an Entity-Attribute-Value model . 所以它实际上做的是尝试从实体 - 属性 - 值模型创建一致的结果集。 These are notoriously difficult to tune. 众所周知,这些很难调整。 EAV suits certain use-cases, such as analytics, but re-constructing a row from an atomized set of columns is very expensive. EAV适合某些用例,例如分析,但是从一组雾化列重新构造一行是非常昂贵的。 They are also tiresome to query (as you now realise!) and also error-prone, because re-construction is a manual process - this probably isn't what you need to return for OIPAREINSURANCETYPE : 它们也很难查询(正如你现在意识到的那样!)并且也容易出错,因为重构是一个手动过程 - 这可能不是你需要为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,

This demonstrates the unsuitability of EAV for most of the cases where it's used. 这表明EAV在大多数情况下都不适合使用。 The schema is still fixed, it's just hard-coded into reads instead of writes. 架构仍然是固定的,它只是硬编码为读取而不是写入。

Of course, EAV is not just hard on those of us who have to query the "model": it also makes it impossible for the database to understand how the data is stored, and so generates bad execution plans. 当然,对于我们这些必须查询“模型”的人来说,EAV并不难:它还使数据库无法理解数据的存储方式,从而产生糟糕的执行计划。

I admit I'm impressed: I can't remember the last time I saw a G in the Rows column of an explain plan. 我承认我印象深刻:我不记得上次在解释计划的Rows看到G了。 That is, your explain plan shows your query is wrestling with ~923,000,000,000 rows which the GROUP BY will boil down to a mere ~7,879,000,000 rows . 也就是说,您的解释计划显示您的查询正在与~923,000,000,000行进行搏斗,其中GROUP BY将归结为仅约7,879,000,000行

So, given how much data you're returning how long do you think it should take? 那么,根据您返回的数据量,您认为应该花多长时间?

Perhaps that final number surprises you. 也许最后的数字让你感到惊讶。 No doubt you were expecting 7789 rows (one per policy). 毫无疑问,你期待7789行(每个政策一行)。 Instead you have a monstrous Cartesian product. 相反,你有一个可怕的笛卡尔积。 Where do all those extra rows come from? 所有这些额外的行来自哪里?

One of the issues is the join on AUDIT_EXT_TEMP_BULK : that adds more than eight hundred rows per policy because there is no filter on that table. 其中一个问题是AUDIT_EXT_TEMP_BULK上的AUDIT_EXT_TEMP_BULK :每个策略添加超过800行,因为该表上没有过滤器。 That's an expensive way to retrieve a policy number, which is presumably fixed for every policy. 这是一种检索策略编号的昂贵方法,可能对每个策略都是固定的。 If there isn't a more sensible way to get this one value (say a column on the ASPOLICY table) replacing that table with an in-line view should reduce the numbers quite a bit: 如果没有更合理的方法来获取这个值(比如ASPOLICY表上的一列),用内联视图替换该表应该会减少相当多的数字:

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

Another thing is the GROUP BY : you actually need to aggregate on just these columns: 另一件事是GROUP BY :你实际上只需聚合这些列:

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

Removing the other columns might improve the explain plan quite considerably. 删除其他列可能会相当大地改进解释计划。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM