我有一个以下查询,需要花费很长时间才能执行。我尝试使用提示并在where子句的列上创建索引,但没有帮助。根据解释计划,总体功能需要更多的成本,对我来说,拥有它们是绝对必要的。无论如何我可以调整它吗?
INSERT
INTO tab3
(CDE,
SOURCE,
SCENARIO,
ID_COUNT,
AMOUNT)
SELECT /*+ parallel(t,8) */ 'BENEFICIARY' AS CDE, 'MTS' AS SOURCE,'Match on Value' AS SCENARIO,COUNT(T.BA1) AS ID_COUNT,SUM(T.AMT) AS AMOUNT
FROM tab1 E
JOIN tab2 T
ON E.AA1 = T.BA1
WHERE (CASE WHEN E.AF1 = 'Y'
THEN replace_word(E.AF2)
ELSE replace_word(E.AF3)
END) = UPPER(TRIM(T.BF1))
AND E.AF5 = '001'
AND E.AF6 = 'Y'
AND T.BF2 = '001';
如果我将此查询作为过程的一部分并选择查询作为游标,然后使用批量收集插入tab3,那会有帮助吗?在此先感谢您的时间。我们的数据库是Oracle 11g。
修改 添加上述查询的解释计划:
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | 127 | | 1458K (1)| 04:51:40 |
| 1 | LOAD TABLE CONVENTIONAL | tab3 | | | | | |
| 2 | SORT AGGREGATE | | 1 | 127 | | | |
|* 3 | HASH JOIN | | 10005 | 1240K| 76M| 1458K (1)| 04:51:40 |
|* 4 | TABLE ACCESS BY INDEX ROWID| tab1 | 1000K| 64M| | 432K (1)| 01:26:33 |
|* 5 | INDEX RANGE SCAN | IDX_AF5 | 2000K| | | 4483 (1)| 00:00:54 |
|* 6 | TABLE ACCESS FULL | AF5 | 3538K| 199M| | 1009K (1)| 03:22:00 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access(CASE "E"."AF1" WHEN 'Y' THEN "REPLACE_WORD"("E"."AF2") ELSE
"REPLACE_WORD"("E"."AF3") END =UPPER(TRIM("T"."BF1")) AND
"E"."AA1"="T"."BA1")
4 - filter("E"."AF6"='Y')
5 - access("E"."AF5"='001')
6 - filter("T"."BF2"='001')
答案 0 :(得分:2)
性能调优需要大量信息。此问题包含完整的查询和执行计划,这远远超过大多数性能问题。但正如Rob van Wijk所提到的,重要的是要知道实际的时间和返回的行,而不仅仅是估计。令人惊讶的是,当实数如此接近时,有多少人只根据估计做出猜测。 Rob的方法会起作用,虽然我更喜欢使用
select dbms_sqltune.report_sql_monitor(sql_id => 'your sql_id') from dual;
以下是基于所提供信息的一些提示:
SELECT /*+ parallel(t,8) */ ...
替换为SELECT /*+ parallel(8) */ ...
。当前查询使用对象级提示,它仅指示优化器考虑使用并行性进行一次全表扫描。语句级别提示告诉优化器对整个语句使用并行性。这可以启用并行索引访问。INSERT /*+ APPEND PARALLEL(8) */ ...
这样的提示可能会有所帮助显著。将LOAD TABLE CONVENTIONAL
更改为直接路径插入LOAD AS SELECT
,有时可以将性能提高几个数量级。让这个工作变得棘手,会话也需要alter session enable parallel dml;
,表可能需要NOLOGGING
,外键可能需要禁用等等。PARALLEL_ENABLE
定义。并且优化器无法估计函数的选择性,尽管有时可以通过associate statistics
来帮助它。如果可能,使用内联视图或其他声明方法替换查询可能更好。此外,你肯定想要删除异常处理程序,除了模糊错误的行号之外什么都不做。exec dbms_stats.gather_table_stats('schema_name', 'E');
。即使我这没有任何改变,这个问题应该始终表明"统计数据是最新的"因为它通常是首先要看的东西。答案 1 :(得分:0)
摆脱从查询中调用函数:
create or replace function fun1(
p_var in varchar2
)
return varchar2
is
begin
return replace(p_var, 'a', 'aaa');
end fun1;
declare
l_start number := dbms_utility.get_cpu_time;
begin
for i in (select fun1(object_name) from all_objects where rownum < 10000)
loop
null;
end loop;
DBMS_OUTPUT.put_line((dbms_utility.get_cpu_time - l_start) || ' hsec');
end;
302 hsec
declare
l_start number := dbms_utility.get_cpu_time;
begin
for i in (select replace(object_name, 'a', 'aaa') from all_objects where rownum < 10000)
loop
null;
end loop;
DBMS_OUTPUT.put_line((dbms_utility.get_cpu_time - l_start) || ' asdf');
end;
268 hsec
正如你所看到的,我有大约0.3秒的利润,这是10K的记录。我每次都跑了好几次蠕虫缓冲区缓存,
答案 2 :(得分:0)
你至少可以做两件事:
使用 RESULT_CACHE IS(http://www.oracle-developer.net/display.php?id=504)
在UPPER上创建功能指数(TRIM(T.BF1))
根据(http://www.dba-oracle.com/oracle_tips_null_idx.htm)索引null列,你可以这样做:
create index
func_idx on
tab2 T
(UPPER(TRIM(T.BF1)), 1);
使用pl / sql无济于事,事情可能会比以前更糟糕。