各种表连接测试
--------------------2013/10/03
Sort Merge Join
--从实验可以发现,Sort Merge Join如它的名字一样,先进行Sort,然后再Merge。这里的表很小,默认采取了Sort Merge Join的方式进行连接。
SQL> select t.ename,p.dname from emp t join dept p on t.deptno=p.deptno;
ENAME DNAME
---------- --------------
CLARK ACCOUNTING
KING ACCOUNTING
MILLER ACCOUNTING
JONES RESEARCH
FORD RESEARCH
ADAMS RESEARCH
SMITH RESEARCH
SCOTT RESEARCH
WARD SALES
TURNER SALES
ALLEN SALES
ENAME DNAME
---------- --------------
JAMES SALES
BLAKE SALES
MARTIN SALES
14 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 844388907
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 308 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN | | 14 | 308 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 14 | 126 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL | EMP | 14 | 126 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T"."DEPTNO"="P"."DEPTNO")
filter("T"."DEPTNO"="P"."DEPTNO")
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
11 consistent gets
0 physical reads
0 redo size
691 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
14 rows processed
使用Hint,将上面SQL以Hash Join方式执行。
--Hint 的使用方式 use_hash(,)
SQL> select /*+use_hash(t,p)*/ t.ename,p.dname from emp t join dept p on t.deptno=p.deptno
ENAME DNAME
---------- --------------
SMITH RESEARCH
ALLEN SALES
WARD SALES
JONES RESEARCH
MARTIN SALES
BLAKE SALES
CLARK ACCOUNTING
SCOTT RESEARCH
KING ACCOUNTING
TURNER SALES
ADAMS RESEARCH
ENAME DNAME
---------- --------------
JAMES SALES
FORD RESEARCH
MILLER ACCOUNTING
14 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 615168685
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 308 | 7 (15)| 00:00:01 |
|* 1 | HASH JOIN | | 14 | 308 | 7 (15)| 00:00:01 |
| 2 | TABLE ACCESS FULL| DEPT | 4 | 52 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 14 | 126 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T"."DEPTNO"="P"."DEPTNO")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
15 consistent gets
5 physical reads
0 redo size
756 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
使用hint让SQL以Nested Join方式执行。
--Hint使用方法 user_nl(,)
SQL> select /*+use_nl(t,p)*/ t.ename,p.dname from emp t join dept p on t.deptno=p.deptno;
ENAME DNAME
---------- --------------
CLARK ACCOUNTING
KING ACCOUNTING
MILLER ACCOUNTING
SMITH RESEARCH
JONES RESEARCH
SCOTT RESEARCH
ADAMS RESEARCH
FORD RESEARCH
ALLEN SALES
WARD SALES
MARTIN SALES
ENAME DNAME
---------- --------------
BLAKE SALES
TURNER SALES
JAMES SALES
14 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4192419542
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 308 | 10 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 14 | 308 | 10 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| DEPT | 4 | 52 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| EMP | 4 | 36 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("T"."DEPTNO"="P"."DEPTNO")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
37 consistent gets
0 physical reads
0 redo size
691 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
为什么Hash Join和Nested Join都没有使用dept上面的索引呢?
这是基于CBO的成本考量,你可以指定优化器采用索引。
那么就要使用多个hint,如下为使用多个hint的方法。
SQL> select /*+use_nl(t,p) index(p pk_dept) leading(p,t) */ t.ename,p.dname from emp t join dept p on t.deptno=p.deptno;
ENAME DNAME
---------- --------------
CLARK ACCOUNTING
KING ACCOUNTING
MILLER ACCOUNTING
SMITH RESEARCH
JONES RESEARCH
SCOTT RESEARCH
ADAMS RESEARCH
FORD RESEARCH
ALLEN SALES
WARD SALES
MARTIN SALES
ENAME DNAME
---------- --------------
BLAKE SALES
TURNER SALES
JAMES SALES
14 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 4130191885
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 308 | 9 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 14 | 308 | 9 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | EMP | 4 | 36 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("T"."DEPTNO"="P"."DEPTNO")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
33 consistent gets
0 physical reads
0 redo size
691 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
除了上面三种连接的具体方式外。我们又经常听说inner join,left join和right join,这些又有什么关系呢?
--上面的三种是SQL优化器采取的实现方式,而我们所说的inner,left,right只是我们的外在需求,实质里面的SQL执行路径还是遵循上述的三种表连接方式。
Inner Join就是只筛选符合on条件的结果集,这里不再详述,这里我们看一下Left Join。
Left Join:以左表为基准,所有列都列出,匹配不到右表的,用NULL表示。
SQL> select /*+use_nl(t,p) index(p pk_dept) leading(p,t) */* from emp t left join dept p on t.deptno=p.deptno;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEPTNO DNAME LOC
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ---------- -------------- -------------
7369 SMITH CLERK 7902 17-DEC-80 800 20 20 RESEARCH DALLAS
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 30 SALES CHICAGO
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 30 SALES CHICAGO
7566 JONES MANAGER 7839 02-APR-81 2975 20 20 RESEARCH DALLAS
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 30 SALES CHICAGO
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30 30 SALES CHICAGO
7782 CLARK MANAGER 7839 09-JUN-81 2450 10 10 ACCOUNTING NEW YORK
7788 SCOTT ANALYST 7566 19-APR-87 3000 20 20 RESEARCH DALLAS
7839 KING PRESIDENT 17-NOV-81 5000 10 10 ACCOUNTING NEW YORK
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 30 SALES CHICAGO
7876 ADAMS CLERK 7788 23-MAY-87 1100 20 20 RESEARCH DALLAS
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEPTNO DNAME LOC
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ---------- -------------- -------------
7900 JAMES CLERK 7698 03-DEC-81 950 30 30 SALES CHICAGO
7902 FORD ANALYST 7566 03-DEC-81 3000 20 20 RESEARCH DALLAS
7934 MILLER CLERK 7782 23-JAN-82 1300 10 10 ACCOUNTING NEW YORK
Execution Plan
----------------------------------------------------------
Plan hash value: 1301846388
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 812 | 17 (0)| 00:00:01 |
| 1 | NESTED LOOPS OUTER | | 14 | 812 | 17 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | EMP | 14 | 532 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T"."DEPTNO"="P"."DEPTNO"(+))
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
26 consistent gets
0 physical reads
0 redo size
1815 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
我们再来看一下Right Join,恰好与Left Join相反,right join以右表为基准,左表匹配不上的拿null表示。
SQL> select /*+use_nl(t,p) index(p pk_dept) leading(p,t) */* from emp t right join dept p on t.deptno=p.deptno;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEPTNO DNAME LOC
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ---------- -------------- -------------
7782 CLARK MANAGER 7839 09-JUN-81 2450 10 10 ACCOUNTING NEW YORK
7839 KING PRESIDENT 17-NOV-81 5000 10 10 ACCOUNTING NEW YORK
7934 MILLER CLERK 7782 23-JAN-82 1300 10 10 ACCOUNTING NEW YORK
7369 SMITH CLERK 7902 17-DEC-80 800 20 20 RESEARCH DALLAS
7566 JONES MANAGER 7839 02-APR-81 2975 20 20 RESEARCH DALLAS
7788 SCOTT ANALYST 7566 19-APR-87 3000 20 20 RESEARCH DALLAS
7876 ADAMS CLERK 7788 23-MAY-87 1100 20 20 RESEARCH DALLAS
7902 FORD ANALYST 7566 03-DEC-81 3000 20 20 RESEARCH DALLAS
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 30 SALES CHICAGO
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 30 SALES CHICAGO
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 30 SALES CHICAGO
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEPTNO DNAME LOC
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ---------- -------------- -------------
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30 30 SALES CHICAGO
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 30 SALES CHICAGO
7900 JAMES CLERK 7698 03-DEC-81 950 30 30 SALES CHICAGO
40 OPERATIONS BOSTON
15 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3107728757
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 812 | 9 (0)| 00:00:01 |
| 1 | NESTED LOOPS OUTER | | 14 | 812 | 9 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 80 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | EMP | 4 | 152 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("T"."DEPTNO"(+)="P"."DEPTNO")
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
33 consistent gets
0 physical reads
0 redo size
1704 bytes sent via SQL*Net to client
416 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed
总结: 以上就是关于表连接的一些内容。