我遇到 Oracle SQL 性能问题。我有一个子选择(比如说 emp 表和其他一些表)并且想要外部连接另一个表(比如说 dep)
select emp.deptid, dep.id
from (
select id, deptid, sal, first_day, last_day
from emp
where xxx
) emp, dep
where emp.deptid = dep.id (+);
运行速度很快,只需几毫秒。但是当我在顶部 SELECT 添加一些其他列时,性能会下降。
select emp.deptid, dep.id, emp.sal, emp.first_day, emp.last_day
from (
select id, deptid, sal, first_day, last_day
from emp
where xxx
) emp, dep
where emp.deptid = dep.id (+);
这怎么可能?如果我在 SELECT 中添加一些列,外连接应该没有什么区别?
向内联视图添加不必要的列通常不会影响性能。但向最外层查询添加不必要的列可能会对性能产生负面影响。
Oracle 执行许多优化,这些优化可能会显着地将您的查询转换为不同但逻辑上等效的查询。例如,内联视图经常与查询的其他部分合并,因此不要期望 Oracle“首先”运行子查询。
逻辑上不必要的列、顺序和联接可能会从 Oracle 运行的查询版本中删除。最外层 select 子句中使用的任何列都必须从数据库中检索。添加的列越多,索引在检索结果中的作用就越小。
例如,在您的第一个查询中,只有 DEP.ID 和 EMP.DEPTID 列是必需的。 DEP.ID 可能是主键,它必须有一个索引。 EMP.DEPTID 是一个外键,并且几乎总是有一个索引。这意味着第一个查询根本不需要访问表 - 所有数据都存储在较小的索引数据结构中。但是您的第二个查询使用了许多列,这些列不太可能被索引。
--drop table dep;
--drop table emp;
create table dep(id number primary key, name varchar2(100));
create table emp
(
id number primary key,
deptid number not null,
sal number,
first_day date,
last_day date,
constraint fk_emp_deptid foreign key(deptid) references dep(id)
);
create index emp_detpid_idx on emp(deptid);
请注意,解释计划显示正在使用两个索引。
explain plan for
select emp.deptid, dep.id
from (
select id, deptid, sal, first_day, last_day
from emp
--where xxx
) emp, dep
where emp.deptid = dep.id (+);
select * from table(dbms_xplan.display(format => '-predicate -note'));
Plan hash value: 2059872495
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 1 (0)| 00:00:01 |
| 1 | NESTED LOOPS OUTER| | 1 | 26 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | EMP_DETPID_IDX | 1 | 13 | 1 (0)| 00:00:01 |
| 3 | INDEX UNIQUE SCAN| SYS_C0029029 | 1 | 13 | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
请注意,解释计划显示正在使用一个索引和一张表。
explain plan for
select emp.deptid, dep.id, emp.sal, emp.first_day, emp.last_day
from (
select id, deptid, sal, first_day, last_day
from emp
--where xxx
) emp, dep
where emp.deptid = dep.id (+);
select * from table(dbms_xplan.display(format => '-predicate -note'));
Plan hash value: 1758309518
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 57 | 2 (0)| 00:00:01 |
| 1 | NESTED LOOPS OUTER| | 1 | 57 | 2 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 1 | 44 | 2 (0)| 00:00:01 |
| 3 | INDEX UNIQUE SCAN| SYS_C0029029 | 1 | 13 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------------
在不了解相关表、索引和查询的情况下,我们无法准确说出出了什么问题。但它可能与上面的例子类似。