比较Oracle中的两个连接查询

时间:2015-02-03 04:30:28

标签: sql oracle join

我有2个查询执行相同的工作:

SELECT * FROM student_info 
INNER JOIN class 
ON student_info.id = class.studentId 
WHERE student_info.name = 'Ken'

SELECT * FROM (SELECT * FROM student_info WHERE name = 'Ken') studInfo
INNER JOIN class 
ON student_info.id = class.studentId

哪一个更快?我猜第二个但不确定,我使用的是Oracle 11g。

更新:

我的表格没有索引,我确认两个PLAN_TABLE_OUTPUT几乎相同:

http://i.imgur.com/wf2FnjZ.png

Full size image

3 个答案:

答案 0 :(得分:3)

在最新版本的Oracle中,优化器非常智能,可以完成其工作。所以它不重要,您的两个查询都将在内部优化以有效地完成任务。优化工具可能会执行查询重写并选择高效执行计划

让我们用一个EMP和DEPT表的小例子来理解这一点。我将在问题中使用与您类似的两个类似查询。

我将采用两种情况,第一种是带有非索引列的谓词,第二种是带有索引列的谓词。

案例1 - 具有非索引列的谓词

SQL> explain plan for
  2  SELECT * FROM emp e
  3  INNER JOIN dept d
  4  ON e.deptno = d.deptno
  5  where ename = 'SCOTT';

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 3625962092

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     1 |    59 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |       |       |            |          |
|   2 |   NESTED LOOPS               |         |     1 |    59 |     4   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL         | EMP     |     1 |    39 |     3   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
|   5 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------

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

   3 - filter("E"."ENAME"='SCOTT')
   4 - access("E"."DEPTNO"="D"."DEPTNO")

Note
-----
   - this is an adaptive plan

22 rows selected.

SQL>
SQL> explain plan for
  2  SELECT * FROM (SELECT * FROM emp WHERE ename = 'SCOTT') e
  3  INNER JOIN dept d
  4  ON e.deptno = d.deptno;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 3625962092

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     1 |    59 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |       |       |            |          |
|   2 |   NESTED LOOPS               |         |     1 |    59 |     4   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL         | EMP     |     1 |    39 |     3   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
|   5 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------

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

   3 - filter("ENAME"='SCOTT')
   4 - access("EMP"."DEPTNO"="D"."DEPTNO")

Note
-----
   - this is an adaptive plan

22 rows selected.

SQL>

案例2 - 具有索引列的谓词

SQL> explain plan for
  2  SELECT * FROM emp e
  3  INNER JOIN dept d
  4  ON e.deptno = d.deptno
  5  where empno = 7788;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 2385808155

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     1 |    59 |     2   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |     1 |    59 |     2   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| EMP     |     1 |    39 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_EMP  |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |
|*  5 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------

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

   3 - access("E"."EMPNO"=7788)
   5 - access("E"."DEPTNO"="D"."DEPTNO")

18 rows selected.

SQL>
SQL> explain plan for
  2  SELECT * FROM (SELECT * FROM emp where empno = 7788) e
  3  INNER JOIN dept d
  4  ON e.deptno = d.deptno;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 2385808155

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     1 |    59 |     2   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |     1 |    59 |     2   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| EMP     |     1 |    39 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_EMP  |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |
|*  5 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------

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

   3 - access("EMPNO"=7788)
   5 - access("EMP"."DEPTNO"="D"."DEPTNO")

18 rows selected.

SQL>

每个案例的解释计划之间是否有任何区别?否。

答案 1 :(得分:1)

您需要向我们展示查询计划和执行统计信息。也就是说,假设name被编入索引且统计数据相当准确,如果两个查询没有生成相同的计划(因此,性能相同),我会感到震惊。使用任一查询,Oracle都可以在评估连接之前或之后评估谓词,因此在两种情况下它不太可能选择不同。

答案 2 :(得分:0)

我肯定会倾向于第一个查询。

当嵌套选择时,Oracle的优化机会较少。它通常必须将内部选择评估为临时视图,然后将外部选择应用于该视图。这很少比Oracle JOIN更快,因为Oracle会一起评估所有内容。

显示您的EXPLAIN PLAN也会为我们提供额外的信息。