三大经典表连接探索(nested loop、hash、merge sort)

1、表的访问次数探索

  • 表的访问次数之NL连接研究

CREATE TABLE t1 (
     id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ;
CREATE TABLE t2 (
     id NUMBER NOT NULL,
     t1_id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ;

execute dbms_random.seed(0);
INSERT INTO t1
     SELECT  rownum,  rownum, dbms_random.string('a', 50)
       FROM dual
     CONNECT BY level <= 100
      ORDER BY dbms_random.random;
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
    ORDER BY dbms_random.random;
COMMIT;


select count(*) from t1;

  COUNT(*)
----------
       100

select count(*) from t2;


  COUNT(*)
----------
    100000

设置statistics_level=all的方式来观察如下表连接语句的执行计划:

--T2表被访问100次(驱动表访问1次,被驱动表访问100次)
--这个set linesize 1000对dbms_xplan.display_cursor还是有影响的,如果没有设置,默认情况下的输出,将会少了很多列,如BUFFERS等
Set linesize 1000
alter session set statistics_level=all ;
SELECT /*+ leading(t1) use_nl(t2)*/ * FROM t1, t2 WHERE t1.id = t2.t1_id;

通过以上的实验说明:在NL连接中,驱动表返回多少条,被驱动表访问多少次。

E-Rows:预测返回的条数

A-Eows:实际返回的条数

Starts:相 关的表被访问几次

Buffer:使用多少内存

  • 表的访问次数之hash连接

构造环境:

DROP TABLE t1 CASCADE CONSTRAINTS PURGE;
DROP TABLE t2 CASCADE CONSTRAINTS PURGE;
CREATE TABLE t1 (
     id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ;
CREATE TABLE t2 (
     id NUMBER NOT NULL,
     t1_id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ;
execute dbms_random.seed(0);
INSERT INTO t1
     SELECT  rownum,  rownum, dbms_random.string('a', 50)
       FROM dual
     CONNECT BY level <= 100
      ORDER BY dbms_random.random;
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
    ORDER BY dbms_random.random;
COMMIT;
select count(*) from t1;

100条
select count(*) from t2;

10000条

set serveroutput off

alter session set statistics_level=all ;

SELECT /*+ leading(t1) use_nl(t2)*/ *
FROM t1, t2
WHERE t1.id = t2.t1_id;
--略去记录结果
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

结论:驱动表与被驱动表只访问一次或者0次。

2、表的驱动顺序与性能的探索

  • 表驱动顺序只nl连接

实验一:小结果集驱动大结果集(NL)

set linesize 1000
alter session set statistics_level=all;
SELECT /*+ leading(t1) use_nl(t2)*/  * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

实验二:大结果集驱动小结果集(NL)

alter session set statistics_level=all;
SELECT /*+ leading(t2) use_nl(t1)*/ * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

实验结论:实验1中,返回的小结果集的表做为了驱动表,实验二中返回结果集过的作为被驱动表。从上面buffes中可以明确的看到,返回小结果集作为驱动表消耗的内存更少,从start来看,实验二中的starts执行了1万次,性能有巨大的差异。

表驱动顺序之hash连接

实验1:小结果集驱动大结果集(HS)

set linesize 1000
alter session set statistics_level=all;
SELECT /*+ leading(t1) use_hash(t2)*/ * FROM t1, t2 WHERE t1.id = t2.t1_id and t1.n=19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

实验二:大结果集驱动小结果集(HS)

set linesize 1000
SELECT /*+ leading(t2) use_hash(t1)*/ * FROM t1, t2 WHERE t1.id = t2.t1_id and t1.n=19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

结论:从以上实验表明,hash连接中小结果集作为驱动表使用的开销更少。可以从OMem 、Used-Mem中可以看出。因为Hash需要排序。

3、表连接是否有排序

  • 表连接之NL连接不需要排序

set linesize 1000
set autotrace traceonly
SELECT /*+ leading(t1) use_nl(t2)*/ * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n = 19;

  • 表连接之HS连接不需要排序
  • 表连接之排序合并连接

DROP TABLE t1 CASCADE CONSTRAINTS PURGE;
DROP TABLE t2 CASCADE CONSTRAINTS PURGE;
CREATE TABLE t1 (
     id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ;
CREATE TABLE t2 (
     id NUMBER NOT NULL,
     t1_id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ;
execute dbms_random.seed(0);
INSERT INTO t1
     SELECT  rownum,  rownum, dbms_random.string('a', 50)
       FROM dual
     CONNECT BY level <= 100
      ORDER BY dbms_random.random;
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
    ORDER BY dbms_random.random;
COMMIT;
select count(*) from t1;
select count(*) from t2;

set linesize 1000
set autotrace traceonly
SELECT /*+ leading(t1) use_merge(t2)*/ * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n = 19;

4、各个连接的限制条件使用限制

  • NL连接使用的限制

支持各种限制 > < <> =

  • HS连接使用的限制

Hash Join不支持大于,小于,不等,LIKE等连接条件! 

  • merge连接的限制

只支持> < 不支持 <> like等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值