Oracle优化器equijoin的3个表

时间:2015-09-23 21:14:29

标签: oracle

我在oracle 11g数据库中有3个表。我再也无法访问跟踪文件或解释计划了。我在日期字段中加入3表,如:

select * from a,b,c where a.date = b.date and b.date = c.date

这需要永远。

当我

select * from a,b,c where a.date = b.date and b.date = c.date and a.date = c.date
它很快。但这应该有所作为吗?

3 个答案:

答案 0 :(得分:1)

不确定,但它看起来像一个传递依赖。那就是a.date = b.date and b.date = c.date然后是a.date = c.date。您可以修改您的查询,而不是像

select a.* 
from a
join b on a.date = b.date
join c on a.date = c.date;

对于所有这3个表,我也会在date列上有一个索引,因为那是您要加入的列。

答案 1 :(得分:1)

显然,如果连接是A = B,B = C ==>,则数据库不会重写查询。 A = C所以它坚持使用它给出的东西。

请考虑以下事项:

create table a (dt date);
create table b (dt date);
create table c (dt date);

现在填写表格,使a是最小的(5行),b是最大的(100行),c是中间的(50行)。另外,所以b和c中的所有行都不会加入到just中以使事情变得更有趣。

insert into a
select to_date('2015-01-01', 'yyyy-mm-dd') + rownum - 1
from dual
connect by level <= 5
;

insert into b
select to_date('2015-01-01', 'yyyy-mm-dd') + mod(rownum, 10)
from dual
connect by level <= 100
;

insert into c
select to_date('2015-01-01', 'yyyy-mm-dd') + mod(rownum, 10)
from dual
connect by level <= 50
;

我现在要绕过统计数据,完全由数据库决定如何制定计划。

取1:没有从a到c的连接:

explain plan for
select *
  from a
     , b 
     , c
where a.dt = b.dt
  and b.dt = c.dt
;

这是计划:

select *
from table(dbms_xplan.display())
;
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |   250 |  6750 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN          |      |   250 |  6750 |     9   (0)| 00:00:01 |
|*  2 |   HASH JOIN         |      |    50 |   900 |     6   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| A    |     5 |    45 |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| B    |   100 |   900 |     3   (0)| 00:00:01 |
|   5 |   TABLE ACCESS FULL | C    |    50 |   450 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("B"."DT"="C"."DT")
   2 - access("A"."DT"="B"."DT")

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

首先,由于没有关于表的统计数据,Oracle首先选择对数据进行采样,因此不会盲目进行。在这种情况下,表a首先连接到b,然后结果连接到c。

Take 2:介绍a.dt = c.dt条件:

explain plan for
select *
  from a
     ,  b 
     ,  c
where a.dt = b.dt
  and b.dt = c.dt
  and a.dt = c.dt
;

select *
from table(dbms_xplan.display())
;
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |    25 |   675 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN          |      |    25 |   675 |     9   (0)| 00:00:01 |
|*  2 |   HASH JOIN         |      |    25 |   450 |     6   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| A    |     5 |    45 |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| C    |    50 |   450 |     3   (0)| 00:00:01 |
|   5 |   TABLE ACCESS FULL | B    |   100 |   900 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."DT"="B"."DT" AND "B"."DT"="C"."DT")
   2 - access("A"."DT"="C"."DT")

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

你去吧。现在已经切换了连接的顺序,Oracle已经获得了额外的连接路径。 (仅供参考,如果仅使用a.dt = b.dt和a.dt = c.dt,这是相同的计划。)

但是,注意什么?估计不再正确。它最终会猜测25行,而不是250行。因此,额外条件实际上会造成一些混乱。

没有b.dt = c.dt,但是,相同的连接路径,不同的估计(与第一个结果相同的最终结果):

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |   250 |  6750 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN          |      |   250 |  6750 |     9   (0)| 00:00:01 |
|*  2 |   HASH JOIN         |      |    25 |   450 |     6   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| A    |     5 |    45 |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| C    |    50 |   450 |     3   (0)| 00:00:01 |
|   5 |   TABLE ACCESS FULL | B    |   100 |   900 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."DT"="B"."DT")
   2 - access("A"."DT"="C"."DT")

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

长篇故事,因为数据库不会为您假设任何连接路径,在查询中添加一个为数据库提供更多选项,因此可以更改其计划......并且计划中的更改可以肯定会影响结果返回的速度。

答案 2 :(得分:0)

这是您的查询.....

select * from a,b,c where a.date = b.date and .date = c.date and a.date = c.date

现在按照我的观点......

SELECT * FROM a
JOIN B USING(date)
JOIN C USING(date);