0

在我的一个项目中,我正在使用 dblink 对 View 进行直接查询,但经过性能检查后发现它的成本很高(很多嵌套循环,高 CPU 使用)。

现在我们找到了一种解决方案,即使用函数在视图中触发这些查询。那么它是正确的解决方案还是有更好的方法来执行此操作。

示例查询和性能报告:

  1. 不使用函数:

询问 :

SELECT t1.,
       t2.
FROM   table1 t1
       join table2 t2
         ON t1.id = t2.id
WHERE  t1.bookingId = '0250014547' 

业绩报告:

SQL> explain plan for SELECT t1., t2. FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id WHERE t1.bookingId = '0250014547';

SQL> select * from table(dbms_xplan.display);

-------------------------------------------------------------------------------------------
| Id  | Operation                        | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |                          |     1 |   331 |     6   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                    |                          |     1 |   331 |     6   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                   |                          |     1 |   299 |     5   (0)| 00:00:01 |
|   3 |    NESTED LOOPS                  |                          |     1 |   210 |     4   (0)| 00:00:01 |
|   4 |     NESTED LOOPS                 |                          |     1 |   185 |     3   (0)| 00:00:01 |
|   5 |      NESTED LOOPS                |                          |     1 |   156 |     2   (0)| 00:00:01 |
|*  6 |       TABLE ACCESS BY INDEX ROWID| GENERAL_ACCT_MAST_TABLE  |     1 |    66 |     1   (0)| 00:00:01 |
|*  7 |        INDEX UNIQUE SCAN         | IDX_GAM_FORACID          |     1 |       |     1   (0)| 00:00:01 |
|   8 |       TABLE ACCESS BY INDEX ROWID| SERVICE_OUTLET_TABLE     |  1694 |   148K|     1   (0)| 00:00:01 |
|*  9 |        INDEX UNIQUE SCAN         | IDX_SERVICE_OUTLET_TABLE |     1 |       |     1   (0)| 00:00:01 |
|  10 |      TABLE ACCESS BY INDEX ROWID | GEN_SCHM_PARM_TABLE      |   356 | 10324 |     1   (0)| 00:00:01 |
|* 11 |       INDEX UNIQUE SCAN          | IDX_GEN_SCHM_PARM_TABLE  |     1 |       |     1   (0)| 00:00:01 |
|* 12 |     TABLE ACCESS BY INDEX ROWID  | ACCT_STATEMENT_TABLE     |    12M|   309M|     1   (0)| 00:00:01 |
|* 13 |      INDEX UNIQUE SCAN           | IDX_ACCT_STATEMENT_TABLE |     1 |       |     1   (0)| 00:00:01 |
|  14 |    TABLE ACCESS BY INDEX ROWID   | CUST_MAST_GEN_TABLE      |    24M|  2119M|     1   (0)| 00:00:01 |
|* 15 |     INDEX UNIQUE SCAN            | IDX_CUST_MAST_GEN_TABLE  |     1 |       |     1   (0)| 00:00:01 |
|  16 |   TABLE ACCESS BY INDEX ROWID    | BRANCH_BIC_TABLE         | 65258 |  2039K|     1   (0)| 00:00:01 |
|* 17 |    INDEX UNIQUE SCAN             | IDX_BRANCH_BIC_TABLE     |     1 |       |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
  1. 使用功能:

询问:

SELECT Funquery1('0250014547')
FROM   dual; 

业绩报告:

SQL> explain plan for select gtt('0252050014577') from dual;

SQL> select * from table(dbms_xplan.display);

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------
4

2 回答 2

2

第二个查询实际上运行得更快吗?

通常,SQL 优化器不知道函数内部发生了什么,函数内部发生的事情不是查询计划的一部分。这意味着您可以在函数内部隐藏大量复杂性,以使查询计划看起来更高效。然而,这并不意味着查询实际上会运行得更快,使用更少的 CPU,执行更少的 I/O 操作等。如果您在函数中放置完全相同的逻辑,则函数执行的查询将具有与原始查询完全相同的计划。除了几个额外的 PL/SQL 到 SQL 上下文转换的(次要)开销之外,您将获得相同的性能。

表上的统计数据是否准确?查询计划中的基数估计是否合理地接近现实?t1.bookingId = '0250014547'谓词的选择性如何?bookingID主键是t1?

您的问题文本谈到了数据库链接,但您发布的查询和查询计划似乎都没有引用远程数据库中的对象。您的问题文本涉及视图,但您发布的查询未提及任何视图。您发布的查询正在连接两个表,查询计划正在连接 7。这些不一致通常会使提供任何建议变得更加复杂。

于 2012-06-20T13:14:38.623 回答
0

贾斯汀 (+1) 完全正确。EXPLAIN PLAN 向您显示对函数的调用,而不是向您显示函数内部发生的任何事情。

在 SQLPlus 中,使用

set autotrace on

这将为您提供语句执行的实际统计信息,包括任何递归 SQL,这未显示在 EXPLAIN PLAN 输出中。

对于更高级的调整,您可以使用 Oracle 跟踪事件 10046。但 SQLPlus“自动跟踪”可能足以满足您的目的。

调整涉及远程数据库上的表/视图的语句(通过 DB_LINK)可能很麻烦,因为您必须调整您提交的语句和发送到远程数据库的语句。

于 2012-06-21T19:25:44.943 回答