从 plsql 块执行查询花费的时间太长

Posted

技术标签:

【中文标题】从 plsql 块执行查询花费的时间太长【英文标题】:query taking too long to execute from plsql block 【发布时间】:2012-11-27 09:53:11 【问题描述】:

单独执行此查询需要 1 秒执行,通过过程执行相同查询需要 20 秒,请帮助我解决此问题

SELECT * FROM
     (SELECT TAB1.*,ROWNUM ROWNUMM FROM
       (SELECT wh.workitem_id, wh.workitem_priority, wh.workitem_type_id, wt.workitem_type_nm,
          wh.workitem_status_id, ws.workitem_status_nm, wh.analyst_group_id,
          ag.analyst_group_nm, wh.owner_uuid, earnings_estimate.pr_get_name_from_uuid(owner_uuid) owner_name,
          wh.create_user_id, earnings_estimate.pr_get_name_from_uuid( wh.create_user_id) create_name, wh.create_ts,
          wh.update_user_id,earnings_estimate.pr_get_name_from_uuid(wh.update_user_id) update_name, wh.update_ts, wh.bb_ticker_id, wh.node_id,
          wh.eqcv_analyst_uuid, earnings_estimate.pr_get_name_from_uuid( wh.eqcv_analyst_uuid) eqcv_analyst_name,
          WH.WORKITEM_NOTE,Wh.PACKAGE_ID ,Wh.COVERAGE_STATUS_NUM ,CS.COVERAGE_STATUS_CD ,Wh.COVERAGE_REC_NUM,I.INDUSTRY_CD INDUSTRY_CODE,I.INDUSTRY_NM
INDUSTRY_NAME,WOT.WORKITEM_OUTLIER_TYPE_NM  as WORKITEM_SUBTYPE_NM
          ,count(1) over() AS total_count,bro.BB_ID BROKER_BB_ID,bro.BROKER_NM BROKER_NAME, wh.assigned_analyst_uuid,earnings_estimate.pr_get_name_from_uuid(wh.assigned_analyst_uuid)
assigned_analyst_name
     FROM earnings_estimate.workitem_type wt,
          earnings_estimate.workitem_status ws,
          earnings_estimate.workitem_outlier_type wot,
          (SELECT * FROM (
               SELECT  WH.ASSIGNED_ANALYST_UUID,WH.DEFERRED_TO_DT,WH.WORKITEM_NOTE,WH.UPDATE_USER_ID,EARNINGS_ESTIMATE.PR_GET_NAME_FROM_UUID(WH.UPDATE_USER_ID)
UPDATE_NAME, WH.UPDATE_TS,WH.OWNER_UUID, EARNINGS_ESTIMATE.PR_GET_NAME_FROM_UUID(OWNER_UUID)
OWNER_NAME,WH.ANALYST_GROUP_ID,WH.WORKITEM_STATUS_ID,WH.WORKITEM_PRIORITY,EARNINGS_ESTIMATE.PR_GET_NAME_FROM_UUID( WI.CREATE_USER_ID) CREATE_NAME, WI.CREATE_TS,
               wi.create_user_id,wi.workitem_type_id,wi.workitem_id,RANK() OVER (PARTITION BY WH.WORKITEM_ID ORDER BY WH.CREATE_TS DESC NULLS LAST, ROWNUM) R,
               wo.bb_ticker_id, wo.node_id,wo.eqcv_analyst_uuid,
               WO.PACKAGE_ID ,WO.COVERAGE_STATUS_NUM ,WO.COVERAGE_REC_NUM,
               wo.workitem_outlier_type_id                             
                     FROM earnings_estimate.workitem_history wh
                     JOIN EARNINGS_ESTIMATE.workitem_outlier wo
                     ON wh.workitem_id=wo.workitem_id
                     JOIN earnings_estimate.workitem wi
                     ON wi.workitem_id=wo.workitem_id
                     AND WI.WORKITEM_TYPE_ID=3
                     and wh.workitem_status_id not in (1,7)
                    WHERE ( wo.bb_ticker_id IN (SELECT  
                           column_value from table(v_tickerlist)  )
            )
      )wh
                       where r=1
                    AND DECODE(V_DATE_TYPE,'CreatedDate',WH.CREATE_TS,'LastModifiedDate',WH.UPDATE_TS) >= V_START_DATE
                    AND decode(v_date_type,'CreatedDate',wh.create_ts,'LastModifiedDate',wh.update_ts) <= v_end_date
                    and decode(wh.owner_uuid,null,-1,wh.owner_uuid)=decode(v_analyst_id,null,decode(wh.owner_uuid,null,-1,wh.owner_uuid),v_analyst_id)
                    ) wh,
          earnings_estimate.analyst_group ag,
          earnings_estimate.coverage_status cs,
          earnings_estimate.research_document rd,
         ( SELECT
             BB.BB_ID ,
              BRK.BROKER_ID,
              BRK.BROKER_NM
          FROM EARNINGS_ESTIMATE.BROKER BRK,COMMON.BB_ID BB
          WHERE  BRK.ORG_ID = BB.ORG_ID
          AND BRK.ORG_LOC_REC_NUM = BB.ORG_LOC_REC_NUM
          AND BRK.primary_broker_ind='Y') bro,
          earnings_estimate.industry i
     WHERE  wh.analyst_group_id = ag.analyst_group_id
      AND wh.workitem_status_id = ws.workitem_status_id
      AND wh.workitem_type_id = wt.workitem_type_id
      AND wh.coverage_status_num=cs.coverage_status_num
      AND wh.workitem_outlier_type_id=wot.workitem_outlier_type_id
      AND wh.PACKAGE_ID=rd.PACKAGE_ID(+)
      AND rd.industry_id=i.industry_id(+)
      AND rd.BROKER_BB_ID=bro.BB_ID(+)
      ORDER BY wh.create_ts)tab1 )
      ;

【问题讨论】:

1) 避免使用旧式连接(它们通常效率较低 AND 不是每个人都知道并理解它们。2) 简化您的查询 - 它太大而无法阅读简化过程你很可能会发现你的问题。 3) 子选择从不对性能有好处 当你说单独执行时,你是什么意思?在 GUI 或 sqlplus 中?另外,如果您在 GUI 上运行它,您是否滚动到最后一行,而不仅仅是看到 1 个“页面”结果返回的时间?在 sqlplus set autotrace traceonly set timing on (run your select) 中执行此操作并将输出粘贴到您的问题中。 在 sqlplus 中执行,结果只有两行 旧式连接的效率一点也不低。 ANSI 连接当然有一些优点(将连接与过滤器分开,允许更复杂的外部连接和更高的可读性),但它们由 SQL 引擎以相同的方式处理(排除错误)。并且“子选择永远不会提高性能”是一种荒谬的概括,对 Oracle 来说根本不正确。 wo.bb_ticker_id IN (SELECT column_value from table(v_tickerlist) ) 我认为这个语句在像 wo.bb_ticker_id IN ('888 yu') 这样的硬编码时会产生问题,它会在一秒钟内通过过程给出结果.但是当作为输入传递给过程时,它需要时间。 【参考方案1】:

我同意这个问题很可能与SELECT column_value from table(v_tickerlist) 有关。

默认情况下,Oracle 估计表函数返回 8168 行。由于您使用单个值测试查询,因此我假设实际值的数量通常要小得多。与任何预测一样,基数估计总是错误的。但它们至少应该在优化器正确完成工作的实际基数范围内。

您可以强制 Oracle 始终使用动态抽样检查大小。这将需要更多时间来生成计划,但在这种情况下可能是值得的。

例如:

SQL> --Sample type
SQL> create or replace type v_tickerlist is table of number;
  2  /

Type created.

SQL> --Show explain plans
SQL> set autotrace traceonly explain;
SQL> --Default estimate is poor.  8168 estimated, versus 3 actual.
SQL> SELECT column_value from table(v_tickerlist(1,2,3));

Execution Plan
----------------------------------------------------------
Plan hash value: 1748000095

----------------------------------------------------------------------------------------------
| Id  | Operation                             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |      |  8168 | 16336 |    16   (0)| 00:00:01 |
|   1 |  COLLECTION ITERATOR CONSTRUCTOR FETCH|      |  8168 | 16336 |    16   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

SQL> --Estimate is perfect when dynamic sampling is used.
SQL> SELECT /*+ dynamic_sampling(tickerlist, 2) */ column_value
  2  from table(v_tickerlist(1,2,3)) tickerlist;

Execution Plan
----------------------------------------------------------
Plan hash value: 1748000095

----------------------------------------------------------------------------------------------
| Id  | Operation                             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |      |     3 |     6 |     6   (0)| 00:00:01 |
|   1 |  COLLECTION ITERATOR CONSTRUCTOR FETCH|      |     3 |     6 |     6   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)

SQL>

如果这没有帮助,请查看您的解释计划(并在此处发布)。找出基数估计最错误的地方,然后尝试找出原因。

【讨论】:

【参考方案2】:

您的查询太大,在批量数据上执行时需要一些时间。尝试放置一些非规范化的临时表,在那里提取数据,然后在临时表之间连接。这将提高性能。

使用此独立查询,不要在子查询中传递任何变量,如下行所示...

WHERE ( wo.bb_ticker_id IN (SELECT 表中的列值(v_tickerlist)

此外,外连接会影响性能。最好实现非规范化的临时表

【讨论】:

查询文本的大小对性能没有影响。就个人而言,我认为制作临时表来优化一个特定的查询并不是一个好方法。

以上是关于从 plsql 块执行查询花费的时间太长的主要内容,如果未能解决你的问题,请参考以下文章

花费很长时间执行复杂的 mySql 查询

无法访问此站点花费了太长时间 - Laravel

OWB 映射挂起或花费太长时间 - 可能锁定?

如何修复'Typescript“正在进行类型检查......”花费太长时间'?

正则表达式验证花费太长时间 c#

花费太长时间来完成操作并使用大量物理内存