运行此查询的最快方法是删除内联视图并使用并行性。
这是运行此答案底部的测试用例的平均秒数。
No Parallel Parallel
Inline View 221 206
No Inline View 167 154
细节
并行执行可以显着提高许多长时间运行的查询的性能。但它需要企业版、充足的资源、合理的配置等。在 11gR2 上,它可能像SELECT /*+ parallel */ * from ...
. 如果您没有企业版,那么像 @pkuderov 的“穷人的并行性”之类的东西可能会有所帮助。
令人惊讶的是,@AndyDan 建议将order by
内联视图移到内部效果如此之好。通常,Oracle 足够聪明,可以为您进行这些简单的查询转换。UNION ALL
Oracle 显然对语句的性能投入了很多心思。它们在物化视图中受支持,有启用和计划USE_CONCAT
之间切换的提示,12c 可以同时执行分支等。奇怪的是他们错过了如此简单的性能修复。OR
UNION
这个问题可能缺少一个重要的细节。如果查询需要一个小时才能运行,则结果不会显示在屏幕上。如果正在存储数据,则大部分执行时间可能用于写入磁盘、记录更改、更新索引等。您应该包含有关如何存储结果的更多信息。
这个问题要求的是效率,而不是性能。从字面上回答,最有效的解决方案是“No Inline View, No Parallel”,因为并行可以消耗大量额外资源而获得一点好处。特别是在我的测试中,因为我在带有单个硬盘驱动器的桌面上运行它。使用 2 个并行线程几乎永远不会使性能翻倍,但在大多数服务器上它应该比我的测试用例做得更好。
测试设置
--Create sample tables with 67 million rows, gather stats, create table to hold results.
create table tablea nologging as
select 'Sam' name, 'Imp01' impfile, timestamp '2012-05-16 09:54:02.477' imptime, 'blah' fieldX, 'abcde' fieldY from dual union all
select 'Ann' name, 'Imp01' impfile, timestamp '2012-05-16 09:54:02.478' imptime, 'blah' fieldX, 'ldkse' fieldY from dual union all
select 'Bart' name, 'Import12' impfile, timestamp '2012-05-16 09:55:37.387' imptime, 'blah' fieldX, 'dkcke' fieldY from dual union all
select 'Sasha' name, 'Import12' impfile, timestamp '2012-05-16 09:55:37.385' imptime, 'blah' fieldX, 'leele' fieldY from dual;
begin
for i in 1 .. 24 loop
insert /*+ append */ into tablea select * from tablea;
commit;
end loop;
end;
/
create table tableb nologging as
select 'Mark' name, 'Imp01' impfile, timestamp '2012-05-16 09:54:02.477' imptime, 'blah' fieldX, 'lslsk' fieldY from dual union all
select 'John' name, 'Import12' impfile, timestamp '2012-05-16 09:55:37.384' imptime, 'blah' fieldX, 'lmwqd' fieldY from dual;
begin
for i in 1 .. 25 loop
insert /*+ append */ into tableb select * from tableb;
commit;
end loop;
end;
/
begin
dbms_stats.gather_table_stats(user, 'TABLEA');
dbms_stats.gather_table_stats(user, 'TABLEB');
end;
/
create table results nologging as select name, impfile, imptime from tablea;
测试查询
--#1: Inline view, no parallel.
insert /*+ append */ into results
SELECT * from
(
SELECT a.Name as field1, a.ImpFile as field2, a.ImpTime
FROM tablea a WHERE a.fieldX = 'blah' AND length(a.fieldY) = 5
UNION ALL
SELECT b.Name as field1, b.ImpFile as field2, b.ImpTime
FROM tableb b WHERE b.fieldX = 'blah' AND length(b.fieldY) = 5
) foo
ORDER BY field1, field2;
--#2: No inline view, no parallel.
insert /*+ append */ into results
SELECT a.Name as field1, a.ImpFile as field2, a.ImpTime
FROM tablea a WHERE a.fieldX = 'blah' AND length(a.fieldY) = 5
UNION ALL
SELECT b.Name as field1, b.ImpFile as field2, b.ImpTime
FROM tableb b WHERE b.fieldX = 'blah' AND length(b.fieldY) = 5
ORDER BY 1, 2;
--#3: Inline view, parallel.
insert /*+ append */ into results
SELECT /*+ parallel(2) */ * from
(
SELECT a.Name as field1, a.ImpFile as field2, a.ImpTime
FROM tablea a WHERE a.fieldX = 'blah' AND length(a.fieldY) = 5
UNION ALL
SELECT b.Name as field1, b.ImpFile as field2, b.ImpTime
FROM tableb b WHERE b.fieldX = 'blah' AND length(b.fieldY) = 5
) foo
ORDER BY field1, field2;
--#4: No inline view, parallel.
insert /*+ append */ into results
SELECT /*+ parallel(2) */ a.Name as field1, a.ImpFile as field2, a.ImpTime
FROM tablea a WHERE a.fieldX = 'blah' AND length(a.fieldY) = 5
UNION ALL
SELECT b.Name as field1, b.ImpFile as field2, b.ImpTime
FROM tableb b WHERE b.fieldX = 'blah' AND length(b.fieldY) = 5
ORDER BY 1, 2;
测试笔记
测试在 12c 上运行。为简单起见,我truncate table results;
在每个查询之后删除了,并且我没有显示查询是如何运行 5 次的,而高值和低值被抛出。在实际场景中,您不仅要尝试衡量select
性能,parallel
还应将提示移到insert
语句中。