最后执行如下SQL:
select t1.empno,t2.ename from scott.emp t1,emp_temp t2;
从上述显示内容可以看出,现在该SQL的执行计划走的是对表EMP_TEMP和表EMP上主键PK_EMP的笛卡儿连接,因为上述SQL中没有指定连接条件。此处执行计划的步骤是首先全表扫描表EMP_TEMP,扫描结果记为结果集1;接着对表EMP上的主键PK_EMP做索引快速全扫描,并将扫描结果load进PGA中,然后对结果集1和结果集2做笛卡儿连接,最后笛卡儿连接的结果就是上述SQL的最终执行结果。执行计划中关键字“BUFFER SORT”就是表示Oracle会借用PGA并把扫描结果load进去,这样做的好处是省掉了相应的缓存在SGA中所带来的种种额外开销(如持有、释放相关Latch等)。PGA常常用来做排序,这可能就是“BUFFER SORT”中关键字SORT的由来。
需要注意的是,BUFFER SORT不一定会排序,也可能会排序,也可能不会。
看一个SQL是否排序,最直观的方法就是查看其统计信息中"sorts(memory)"和"sorts(disk)"的值,如果这两个指标的值大于0,则说明该SQL在执行时经历过排序。但遗憾的是,这两个指标对BUFFER SORT而言是不准的,此时我们就需要借助目标SQL真实执行计划中"Column Projection Information"部分"keys"的值来判断到底所对应的BUFFER SORT有没有排序。"#keys"的值就表示该执行步骤实际排序列的数量,如果"#keys"值大于0时,则表示该执行步骤确实排过序了。
看如下SQL:
set autotrace traceonly
zx@MYDB>select t1.ename,t2.loc from scott.emp t1,scott.dept t2;
56 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2034389985
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 56 | 784 | 10 (0)| 00:00:01 |
| 1 | MERGE JOIN CARTESIAN| | 56 | 784 | 10 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | DEPT | 4 | 32 | 3 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 14 | 84 | 7 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMP | 14 | 84 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
315 recursive calls
0 db block gets
70 consistent gets
11 physical reads
0 redo size
1831 bytes sent via SQL*Net to client
557 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
7 sorts (memory)
0 sorts (disk)
56 rows processed
注意到上述显示内容中“统计信息”部分的sorts(memory)的值为7,但由于该SQL中出现了ID=3的执行步骤“BUFFER SORT”,所以这并不一定能说明该SQL在执行时经历过排序。
我们来看一下执行坟墓中id=3的执行步骤“BUFFER SORT”所对应的“#keys”的值:
zx@MYDB>select sql_id,sql_text from v$sql where sql_text = 'select t1.ename,t2.loc from scott.emp t1,scott.dept t2';
SQL_ID SQL_TEXT
-------------------- ----------------------------------------------------------------------------------------------------
3dmxcxk72fwr4 select t1.ename,t2.loc from scott.emp t1,scott.dept t2
zx@MYDB>select * from table(dbms_xplan.display_cursor('3dmxcxk72fwr4',0,'advanced'));