在 SELECT 中添加列时,SQL 在外连接时速度较慢

问题描述 投票:0回答:1

我遇到 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 中添加一些列,外连接应该没有什么区别?

sql oracle-database sqlperformance
1个回答
0
投票

向内联视图添加不必要的列通常不会影响性能。但向最外层查询添加不必要的列可能会对性能产生负面影响。

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 |
-----------------------------------------------------------------------------------

在不了解相关表、索引和查询的情况下,我们无法准确说出出了什么问题。但它可能与上面的例子类似。

© www.soinside.com 2019 - 2024. All rights reserved.