PL/SQL 匿名块中的查询执行速度很慢
Query execution is slow in PL/SQL anonymous block
Oracle PL/SQL 中的查询 运行 很慢。在 PL/SQL 中大约需要 8 分钟,而在 SQL Editor 或 SQL Plus 中 运行 只需要 4 秒。
请告诉我这是什么原因造成的。 SQL 和 PL/SQL 是否有可能选择不同的执行计划?
----SQL Editor query---takes 4 seconds---400 row count--
SELECT count(*) FROM
(
SELECT col1, col2
FROM
my_tab1 t1, my_tab2 t2
WHERE
t1.pk_col1=t2.pk_col1
and t1.created_date < t2.created_date
)
--PL/SQL Code--takes about 8 minutes---400 row rount--
DECLARE
v_cnt PLS_INTEGER:=0;
BEGIN
SELECT count(*) INTO v_cnt
FROM
(
SELECT col1, col2
FROM
my_tab1 t1, my_tab2 t2
WHERE
t1.pk_col1=t2.pk_col1
and t1.created_date < t2.created_date
)
END;
/
在匿名块中捕获执行计划的最简单方法是在循环中调用 dbms_xplan.display_cursor
并打印每一行输出:
declare
v_cnt pls_integer;
begin
execute immediate 'alter session set statistics_level = ALL';
select count(*) into v_cnt
from
(
select col1, col2
from my_tab1 t1, my_tab2 t2
where t1.pk_col1 = t2.pk_col1
and t1.created_date < t2.created_date
);
for r in (
select p.plan_table_output
from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST -OUTLINE +NOTE +PREDICATE +IOSTATS +REPORT')) p
)
loop
dbms_output.put_line(r.plan_table_output);
end loop;
end;
您可以在执行 SQL 语句后立即从 SQL*Plus 命令提示符进行相同的调用,但您首先必须禁用 dbms_output,否则 SQL 语句不是您所做的 'last' 语句。 (如果您知道,也可以指定 sql_id。)有关详细信息,请参阅 dbms_xplan documentation.
set serverout off
alter session set statistics_level = ALL;
select count(*)
from
(
select col1, col2
from my_tab1 t1, my_tab2 t2
where t1.pk_col1 = t2.pk_col1
and t1.created_date < t2.created_date
);
select p.plan_table_output
from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST +OUTLINE +ADAPTIVE +PARTITION +NOTE')) p;
有关在一行中调用它的便捷脚本,请参阅 www.williamrobertson.net/documents/xplanx.html。那么就是
select count(*)
from
(
select col1, col2
from my_tab1 t1, my_tab2 t2
where t1.pk_col1 = t2.pk_col1
and t1.created_date < t2.created_date
)
@xplanx
Oracle PL/SQL 中的查询 运行 很慢。在 PL/SQL 中大约需要 8 分钟,而在 SQL Editor 或 SQL Plus 中 运行 只需要 4 秒。
请告诉我这是什么原因造成的。 SQL 和 PL/SQL 是否有可能选择不同的执行计划?
----SQL Editor query---takes 4 seconds---400 row count--
SELECT count(*) FROM
(
SELECT col1, col2
FROM
my_tab1 t1, my_tab2 t2
WHERE
t1.pk_col1=t2.pk_col1
and t1.created_date < t2.created_date
)
--PL/SQL Code--takes about 8 minutes---400 row rount--
DECLARE
v_cnt PLS_INTEGER:=0;
BEGIN
SELECT count(*) INTO v_cnt
FROM
(
SELECT col1, col2
FROM
my_tab1 t1, my_tab2 t2
WHERE
t1.pk_col1=t2.pk_col1
and t1.created_date < t2.created_date
)
END;
/
在匿名块中捕获执行计划的最简单方法是在循环中调用 dbms_xplan.display_cursor
并打印每一行输出:
declare
v_cnt pls_integer;
begin
execute immediate 'alter session set statistics_level = ALL';
select count(*) into v_cnt
from
(
select col1, col2
from my_tab1 t1, my_tab2 t2
where t1.pk_col1 = t2.pk_col1
and t1.created_date < t2.created_date
);
for r in (
select p.plan_table_output
from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST -OUTLINE +NOTE +PREDICATE +IOSTATS +REPORT')) p
)
loop
dbms_output.put_line(r.plan_table_output);
end loop;
end;
您可以在执行 SQL 语句后立即从 SQL*Plus 命令提示符进行相同的调用,但您首先必须禁用 dbms_output,否则 SQL 语句不是您所做的 'last' 语句。 (如果您知道,也可以指定 sql_id。)有关详细信息,请参阅 dbms_xplan documentation.
set serverout off
alter session set statistics_level = ALL;
select count(*)
from
(
select col1, col2
from my_tab1 t1, my_tab2 t2
where t1.pk_col1 = t2.pk_col1
and t1.created_date < t2.created_date
);
select p.plan_table_output
from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST +OUTLINE +ADAPTIVE +PARTITION +NOTE')) p;
有关在一行中调用它的便捷脚本,请参阅 www.williamrobertson.net/documents/xplanx.html。那么就是
select count(*)
from
(
select col1, col2
from my_tab1 t1, my_tab2 t2
where t1.pk_col1 = t2.pk_col1
and t1.created_date < t2.created_date
)
@xplanx