您的位置:首页 > 产品设计 > UI/UE

Why are some of the tables in my query missing from the plan?

2013-12-30 17:28 453 查看
原文:http://optimizermagic.blogspot.com/2008/06/why-are-some-of-tables-in-my-query.html

In 10gR2, we introduced a new transformation, table elimination (alternately called "join elimination"), which removes redundant tables from a query. A table is redundant if its
columns are only referenced to in join predicates, and it is guaranteed that those joins neither filter nor expand the resulting rows. There are several cases where Oracle will eliminate a redundant table. We will discuss each case in turn.

在oracle1ogr2中,引入了一种新的转换技术,表消除(或者可以称为“连接消除”),该技术可以将查询中多余的表移除掉。在查询中,如果某张表的列仅仅在连接谓词中出现过,那么可以确定的是该表不会过滤或者扩展查询结果集。在很多中情况下,oracle都会采取表消除。下面我们来一一讨论每种可能发生的情况。

Primary Key-Foreign Key Table Elimination

Starting in 10gR2, the optimizer eliminates tables that are redundant due to primary key-foreign key constraints. Consider the following example tables:

在10gr2开始,优化器会将存在主外建约束的冗余表消除,考虑下面的情况

create table jobs 
(

job_id NUMBER PRIMARY KEY,
job_title VARCHAR2(35) NOT NULL,
min_salary NUMBER,
max_salary NUMBER

);
create table departments 
(
department_id NUMBER PRIMARY KEY,

department_name VARCHAR2(50)
);
create table employees
(
employee_id NUMBER PRIMARY KEY,
employee_name VARCHAR2(50),
department_id NUMBER REFERENCES departments(department_id),

job_id NUMBER REFERENCES jobs(job_id)
);

and the query:

select e.employee_name
from employees e, departments d
where e.department_id = d.department_id; 

In this query, the join to departments is redundant. The only column referenced in the query appears in the join predicate, and the primary key-foreign key constraint guarantees
that there is at most one match in departments for each row in employees. Hence, the query is equivalent to:

在上面的查询中,对表department的查询是多余的。在该查询中,仅仅在连接谓词中引用了department表中的俩,在主外建约束保证了在employee表中的每一列在department中最多存在一条记录与之对应,因此该查询与下面的查询是等价的。

select e.employee_name
from employees e

where e.department_id is not null; 

The optimizer will generate this plan for the query:

优化器会生成如下的执行计划

-------------------------------------------
Id   Operation             Name
-------------------------------------------
0  SELECT STATEMENT
*  1   TABLE ACCESS FULL    EMPLOYEES
-------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPARTMENT_ID" IS NOT NULL)


Note that the IS NOT NULL predicate
is not necessary if the column has a NOT NULL constraint on it.

如果在列department_id上存在非空约束,那么not null 过滤谓词并不是必须的。

Starting in 11gR1, the optimizer will also eliminate tables that are semi-joined or anti-joined. Consider the following query:

在11gr1开始,oracle对于半连接和反连接也会使用表消除技术,考虑下面的查询

select e.employee_id, e.employee_name
from employees e
where not exists (select 1
from jobs j
where j.job_id = e.job_id);


Since employees.job_id is
a foreign key to jobs.job_id, any non-null value inemployees.job_id must
have a match in jobs. So only employees with null values foremployees.job_id will
appear in the result. Hence, this query is equivalent to:

因为表employees的job_id列是表jobs的外键列,任何employees.job_id的非空值在表jobs中都会存在对于记录,因此只有employees.job_id为空的记录会出现在结果集中,因此该查询等价于下面的查询

select e.employee_id, e.employee_name
from employees e

where job_id is null;

and the optimizer can choose this plan: 生成如下的执行计划

-------------------------------------------
Id   Operation             Name
-------------------------------------------
0  SELECT STATEMENT
*  1   TABLE ACCESS FULL    EMPLOYEES
-------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."JOB_ID" IS NULL)


Suppose employees.job_id has
a NOT NULL constraint: 如果employees.job_id具有非空约束

alter table employees modify job_id not null;

In this case, there could not possibly be any rows in EMPLOYEES,
and the optimizer could choose this plan:

此时employees不会存在满足条件的记录,因此优化器生成如下的执行计划

-------------------------------------------
Id   Operation             Name
-------------------------------------------
0  SELECT STATEMENT
*  1   FILTER
2    TABLE ACCESS FULL   EMPLOYEES
-------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NULL IS NOT NULL)


The "NULL IS NOT NULL"
filter is a false constant predicate, that will prevent the table scan from even taking place.

"NULL IS NOT NULL"
过滤谓词始终为假,因此会阻止对表的扫描事件发生


Also in 11gR1, the optimization became available for ANSI compliant joins. For this query:

从11gR1开始,优化器对符合ANSI标准的查询语句也会使用表消除,如下面的查询

select employee_name
from employees e inner join jobs j 
on e.job_id = j.job_id;

the optimizer can eliminate JOBS and
produce this plan:

-------------------------------------------
Id   Operation             Name
-------------------------------------------
0  SELECT STATEMENT
1   TABLE ACCESS FULL    EMPLOYEES
-------------------------------------------


Outer Join Table Elimination

In 11gR1, a new form of table elimination was introduced for outer joins, which does not require PK-FK constraints. For the example, we require a new table and an addition to EMPLOYEES:

从11gR1开始,oracle对外连接查询也会执行表消除,这种消除技术不需要存在主外建约束。例如,创建如下的新表并对employees添加新列

create table projects
(
project_id NUMBER UNIQUE,
deadline DATE,
priority NUMBER
);

alter table employees add project_id number;

Now consider a query that outer joins employees and projects:

考虑下面的查询:表employees和projects之间存在外连接

select e.employee_name, e.project_id
from employees e, projects p
where e.project_id = p.project_id (+);

The outer join guarantees that every row in employees
will appear at least once in the result. The unique constraint on projects.project_id guarantees
that every row in employees will match at most one row in projects.
Together, these two properties guarantee that every row inemployees will appear in the result
exactly once. Since no other columns from projects are referenced,  projects can
be eliminated, and the optimizer can choose this plan:

外连接保证了在employees中的每条记录都会至少出现在结果集中一次。而project.project_id上的唯一约束保证了在employee中的每条记录之多与project的一条记录向匹配。最终保证了在employees中的每条记录都会在结果集中出现一次,而projects中的列没有出现在结果集中,因此表project被消除,优化器产生如下执行计划

-------------------------------------------
Id   Operation             Name
-------------------------------------------
0  SELECT STATEMENT
1   TABLE ACCESS FULL    EMPLOYEES
-------------------------------------------


Why Would I Ever Write Such a Query?


All of the example queries in this post are very simple, and one would be unlikely to write a query where the join is so obviously unnecessary. There are many real world scenarios
where table elimination may be helpful, including machine-generated queries and elimination of tables in views. For example, a set of tables might be exposed as a view, which contains a join. The join may be necessary to retrieve all of the columns exposed
by the view. But some users of the view may only access a subset of the columns, and in this case, the joined table can be eliminated.

上面的示例是非常简单的,人们也不可能会编写存在明显的表消除的查询语句。但是在现实场景中表消除可能是非常有用的,例如对于机器生产语句和视图中的表消除。例如,在视图中引入了大量的表,并且包含连接。这些连接对于获取视图中的所有列是必须的,但是某些优化可能仅仅需要访问一部分列,在这种情况下,连接表就是可以消除的。

For example, consider the view:

create view employee_directory_v as
select e.employee_name, d.department_name, j.job_title
from employees e, departments d, jobs j
where e.department_id = d.department_id
and e.job_id = j.job_id;

This view might be exposed to a simple employee directory application. To lookup employee names by job title, the application issues a query:

select employee_name
from employee_directory_v
where department = 'ACCOUNTING';

Since the job_title column
is not referenced, jobs can be eliminated from the query, and the optimizer can choose this
plan:

--------------------------------------------
Id   Operation             Name
--------------------------------------------
0  SELECT STATEMENT
*  1   HASH JOIN
2    TABLE ACCESS FULL   EMPLOYEES
*  3    TABLE ACCESS FULL   DEPARTMENTS
--------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
3 - filter("D"."DEPARTMENT_NAME"='ACCOUNTING')


Known Limitations

There are currently a few limitations of table elimination: 对于表消除存在如下限制
Multi-column primary key-foreign key constraints are not supported. 多列主键是不被支持的
Referring to the join key elsewhere in the query will prevent table elimination. For an inner join, the join keys on each side of the join are equivalent, but if the query contains other references to the join key from the table that could otherwise be
eliminated, this prevents elimination. A workaround is to rewrite the query to refer to the join key from the other table (we realize this is not always possible).如果在其他位子引用了连接关键字,将会阻止表消除。对于内连接,连接条件两边的连接关键字是相等连接,但是如果查询中的其他位置引用了可能消除的表中的连接关键字,那么表消除是不可能发生的。当然我们可以引用另外一张表中的连接列,从而保证表消除可以发生(并不是总有效)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  oracle optimizer
相关文章推荐