数据库(oracle)如何连接处理过滤条件

Kam*_*mal 0 database oracle join

当我们在Oracle中的两个表之间创建连接时,在一个或两个表上有一些额外的过滤条件,oracle将首先连接表,然后过滤或首先过滤条件然后加入.

或者简单来说,这两个中哪一个是更好的查询

假设我们有2个员工和部门表,我希望员工所有员工+部门详细信息,员工薪水大于50000

查询1:从员工e,部门d中选择e.name,d.name,其中e.dept_id = d.id,e.salary> 50000;

查询2:选择e.name,d.name from(select*from employee where salary> 50000)e,department d where e.dept_id = d.id;

Ste*_*ell 5

通常它会首先尽可能地过滤.从解释计划中,您实际上可以看到过滤的完成位置以及加入的位置,例如,创建一些表和数据:

create table employees (id integer, dept_id integer, salary number);

create table dept (id integer, dept_name varchar2(10));

insert into dept values (1, 'IT');

insert into dept values (2, 'HR');

insert into employees
select level, mod(level, 2) + 1, level * 1000
from dual connect by level <= 100;

create index employee_uk1 on employees (id);

create index dept_uk1 on dept (id);

exec dbms_stats.gather_table_stats(user, 'DEPT');
Run Code Online (Sandbox Code Playgroud)

现在,如果我解释您提供的两个查询,您会发现Oracle将每个查询转换为幕后的相同计划(它并不总是按照您的想法执行 - Oracle有权'重写'查询,并且它做得很多):

explain plan for
select e.*, d.*
from employees e, dept d
where e.dept_id = d.id
and e.salary > 5000;

select * from table(dbms_xplan.display());

    ------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |    96 |  1536 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN                  |           |    96 |  1536 |     6  (17)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT      |     2 |    12 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | DEPT_UK1  |     2 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |           |    96 |   960 |     4  (25)| 00:00:01 |
|*  5 |    TABLE ACCESS FULL         | EMPLOYEES |    96 |   960 |     3   (0)| 00:00:01 |

4 - access("E"."DEPT_ID"="D"."ID")
    filter("E"."DEPT_ID"="D"."ID")
5 - filter("E"."SALARY">5000)
Run Code Online (Sandbox Code Playgroud)

请注意应用于查询的筛选操作.现在解释替代查询:

explain plan for
select e.*, d.*
from (select * from employees where salary > 5000) e, dept d
where e.dept_id = d.id;

------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |    96 |  1536 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN                  |           |    96 |  1536 |     6  (17)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT      |     2 |    12 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | DEPT_UK1  |     2 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |           |    96 |   960 |     4  (25)| 00:00:01 |
|*  5 |    TABLE ACCESS FULL         | EMPLOYEES |    96 |   960 |     3   (0)| 00:00:01 |    

4 - access("EMPLOYEES"."DEPT_ID"="D"."ID")
    filter("EMPLOYEES"."DEPT_ID"="D"."ID")
5 - filter("SALARY">5000)
Run Code Online (Sandbox Code Playgroud)

一旦您学习了解如何获取解释计划以及如何阅读它们,您通常可以了解Oracle在执行查询时所做的工作.