在我的一个项目中,我使用dblink触发了对View的直接查询,但是在执行了性能检查后发现它很昂贵(很多是嵌套循环,高CPU使用)。
现在我们找到了一个解决方案,即使用函数在视图上触发这些查询。这是正确的解决方案还是有更好的方法来执行此操作。
示例查询和绩效报告:
查询:
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 |
-------------------------------------------------------------------------------------------
查询:
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 |
-----------------------------------------------------------------
答案 0 :(得分:2)
第二个查询实际上运行得更快吗?
通常,SQL优化器不知道函数内部发生了什么,函数内部的内容不是查询计划的一部分。这意味着您可以隐藏函数内部的大量复杂性,以使查询计划看起来更有效。但是,这并不意味着查询实际上运行得更快,使用更少的CPU,执行更少的I / O操作等。如果您在函数内部使用完全相同的逻辑,则函数执行的查询将与原始查询具有完全相同的计划。除了几个额外的PL / SQL到SQL上下文转换的(次要)开销之外,您将获得相同的性能。
表格的统计数据是否准确?查询计划中的基数估计是否合理地接近现实? t1.bookingId = '0250014547'
谓词的选择性如何? bookingID
的主键是t1
吗?
您的问题文本讨论了数据库链接,但您发布的查询和查询计划似乎都没有引用远程数据库中的对象。您的问题文本讨论了一个视图,但您发布的查询并未引用任何视图。您发布的查询正在加入两个表,查询计划正在加入7.这些不一致通常会使提供任何建议变得更加复杂。
答案 1 :(得分:0)
贾斯汀(+1)完全正确。 EXPLAIN PLAN向您显示对该函数的调用,并没有向您显示该函数内发生的任何事情。
在SQLPlus中,使用
set autotrace on
这将为您提供语句执行的实际统计信息,包括任何递归SQL,它不会显示在EXPLAIN PLAN输出中。
对于更高级的调优,您可以使用Oracle跟踪事件10046.但SQLPlus“autotrace”可能足以满足您的需要。
调整涉及远程数据库上的表/视图的语句(通过DB_LINK)可能很麻烦,因为您必须同时调整您提交的语句和发送到远程数据库的语句。