解读 Oracle12c 执行计划——HASH JOIN

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/seagal890/article/details/82826513

解读 Oracle12c 执行计划——HASH JOIN

Oracle官方文档中的解释如下:

Hash Joins - Hash joins are used for joining large data sets. The optimizer uses the smaller of the two tables or data sources to build a hash table, based on the join key, in memory. It then scans the larger table, and performs the same hashing algorithm on the join column(s). It then probes the previously built hash table for each value and if they match, it returns a row.

优化器使用两个表或数据源中较小的一个来在内存中基于连接键构建哈希表。然后扫描较大的表,并在连接列上执行相同的哈希算法。然后,为每个值探测先前构建的哈希表,如果它们匹配,则返回一行。


Nested Loops joins - Nested loops joins are useful when small subsets of data are being joined and if there is an efficient way of accessing the second table (for example an index look up). For every row in the first table (the outer table), Oracle accesses all the rows in the second table (the inner table). Consider it like two embedded FOR loops. In Oracle Database 11g the internal implementation for nested loop joins changed to reduce overall latency for physical I/O so it is possible you will see two NESTED LOOPS joins in the operations column of the plan, where you previously only saw one on earlier versions of Oracle.

嵌套循环连接在连接小数据子集时很有用,如果有一种访问第二表的有效方法(例如,索引查找)。对于第一个表(外表)中的每一行,Oracle访问第二个表(内部表)中的所有行。把它看成是两个嵌入的循环。在Oracle Database 11g中,对嵌套循环连接的内部实现进行了更改,以减少物理I/O的整体延迟,因此在计划的操作列中可能会看到两个NESTED LOOPS连接,在此之前只在Oracle的早期版本中看到一个。

我们使用一个简单的SQL语句来作为例子进行分析:

SELECT
  /*+ GATHER_PLAN_STATISTICS */
  e.first_name,
  e.last_name,
  e.salary,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id  = d.department_id
AND d.department_name IN ('Marketing','Sales');

在 Oracle 11g 数据库版本中,执行计划如下:

Oracle 11g数据库为了减少物理IO的整体延迟,可能会有两个Nested Loop连接行源出现在原来只有一个行源的地方。Oracle数据库会先分配一个Nested Loop连接行源,它用内部表的索引作为内部表,外部表的值作为外部表,用索引和值做第一次连接。而另一个行源使用内部表连接第一个连接的结果,内部表的索引中有行ID。

上图中,执行计划第1步中,来自于DEPARTMENTS表的行组成第1个连接的外部表。第1个连接的内部表是索引EMP_DEPARTMENT_IX。第1个连接的结果组成第2个连接的外部表,这个连接的内部表是EMPLOYEES表。

在下列情况下第2个连接的行源不会被分配,执行计划看起来与Oracle 10g以前一样:

  • 所有内连接需要的列都已经出现在索引中没有必要进行表访问。这时,数据库只分配一个连接源。
  • 返回的行顺序可能与以前版本有所不同。当Oracle数据库想要让行的顺序与以前一样(例如:想要避免ORDER BY排序)时,就有可能使用原来的NESTED LOOP连接实现方法。
  • OPTIMIZER_FEATURES_ENABLE初始化参数被设置为与Oracle 11g之前版本中的一样。这时,Oracle数据库会使用原来的NESTED LOOP连接实现方法。

在Oracle 12c 中,执行SQL语句后,

使用下面的语句查看执行计划

SQL> SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format => 'adaptive allstats last'));

执行计划如图所示:

如何解读这个执行计划呢?

这个是Oracle 12c Adaptive Query Optimization 的功能。上图中执行计划带有 “-” 号的部分(1,4,8)。

Oracle 的查询优化器认为 Nested Loop不是最优的表连接方法,而使用 Hash Join进行连接。

查询优化器何时使用HASH JOIN呢?

如果两个表使用等值连接,并且以下任何条件成立时,那么查询优化器就是用HASH JOIN连接来连接两个表:

1、大量数据必须被连接;

2、一个小表的很大部分数据需要被连接。

如果在查询语句中去掉 /*+ GATHER_PLAN_STATISTICS */ Hints提示,而将语句修改为:

SELECT
  e.first_name,
  e.last_name,
  e.salary,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id  = d.department_id
AND d.department_name IN ('Marketing','Sales');

然后再次查看执行计划:

我们发现执行计划已经发生了改变,使用了两层的 NESTED LOOP 进行连接。

根据Oracle 12c 的官方文档解释:

Based on the information seen in the statistics collector, the optimizer will make the decision about which sub-plan to use.

Oracle 12c 的查询优化器会根据评估的结果,选择采用NESTED LOOP JOIN 还是采用 HASH JOIN连接。

(完)

猜你喜欢

转载自blog.csdn.net/seagal890/article/details/82826513