什么是“partition-wise join”呢?我们将用一个比喻来解释它的好处。

假设两个人,Logan和Shannon,决定住在一起。如果他们每个人都已经有了自己的住所,他们就会拥有很多你在任何家庭都能找到的普通物品。所以他们要做一个决定——是每样东西都保留两件,还是对它们的共同点进行“筛选”。在这个假想的场景中,我们将关注浴室和厨房中的家庭用品。Logan拿起一套厨刀和一个刀板,打电话问Shannon:“嘿,Shannon,你已经有一个刀架了吗?”

你觉得Shannon会怎么做?在整栋房子里找一个现有的刀板?当然不是。如果有刀板,那么它唯一的位置就是厨房。事实上,当Shannon和Logan在整所房子里匹配物品时,他们会把调查范围限制在对有问题的物品有意义的房间里。这是常识——为什么会有人在浴室里找(比如说)叉子和勺子呢?那只是白费力气。(编者注:任何有小孩的人当然会对这个比喻提出异议,他们会非常正确地指出,你可能在每个房间里都能找到所有可能的家居用品,可能在外面也能找到,但为了讨论的方便,我们将省略这种可能性)

这正是Partition-Wise Join使我们能够在数据库中做到的。如果两个表分区具有相同的定义,我们在分区键上进行join,那么定义保证对于表中位于分区P、分区键为k的行,我们只需要在要连接的表中的相同的分区中找对应的行(相同是基于分区定义的)。这种划分相当于“只在厨房里搜索,而不是在浴室”。在执行这样的连接时,我们可以通过执行计划看到这一点。让我们创建两个分区定义相等的表,然后在分区键上连接。

SQL> --
SQL> -- Example 1
SQL> --
SQL>
SQL> drop table t1 purge; Table dropped. SQL> drop table t2 purge; Table dropped. SQL>
SQL> create table t1 ( x int, y int )
2 partition by range ( x )
3 (
4 partition p_kitchen values less than (10000),
5 partition p_bathroom values less than (20000),
6 partition p_dining values less than (30000)
7 ); Table created. SQL>
SQL>
SQL> create table t2 ( x int, y int )
2 partition by range ( x )
3 (
4 partition p_kitchen values less than (10000),
5 partition p_bathroom values less than (20000),
6 partition p_dining values less than (30000)
7 ); Table created. SQL>
SQL>
SQL> insert into t1 select rownum, rownum from dual connect by level < 30000; 29999 rows created. SQL> insert into t2 select * from t1; 29999 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats('','t1') PL/SQL procedure successfully completed. SQL> exec dbms_stats.gather_table_stats('','t2') PL/SQL procedure successfully completed. SQL>
SQL> --
SQL> set autotrace traceonly explain
SQL> select count(t1.y), count(t2.y)
2 from t1,t2
3 where t1.x = t2.x; Execution Plan
----------------------------------------------------------
Plan hash value: 3155849676 ---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 1641 (1)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 20 | | | | |
| 2 | PARTITION RANGE ALL| | 29999 | 585K| 1641 (1)| 00:00:01 | 1 | 3 |
|* 3 | HASH JOIN | | 29999 | 585K| 1641 (1)| 00:00:01 | | |
| 4 | TABLE ACCESS FULL| T1 | 29999 | 292K| 820 (1)| 00:00:01 | 1 | 3 |
| 5 | TABLE ACCESS FULL| T2 | 29999 | 292K| 820 (1)| 00:00:01 | 1 | 3 |
--------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 3 - access("T1"."X"="T2"."X") SQL> set autotrace off
SQL>

这里执行计划的关键部分是,hash join发生在分区范围内(或“under”分区范围内)的所有迭代中。这可以解释为:“从每个表中的第一个分区开始,对该分区执行散列连接。然后移动到下一个分区;在那个分区上执行散列连接”,等等。这在资源上是有效的,因为在任何情况下我们都不会尝试(显然是失败的)将表T1分区P_KITCHEN连接到表T2分区P_BATHROOM或P_DINING。每个散列连接是一个较小的操作,因此也更有可能在该会话的可用PGA分配中完成。而且,当涉及到并行运行这样的查询时,每个并行的奴隶进程都可以处理将一个分区对其他奴隶进程隔离的工作。

如果分区没有对齐(请参阅前面的编辑器注释),那么我们的连接就没有那么有效。

SQL> --
SQL> -- Example 2
SQL> --
SQL>
SQL>
SQL> drop table t2 purge; Table dropped. SQL> create table t2 ( x int, y int )
2 partition by range ( x )
3 (
4 partition p1 values less than (15000),
5 partition p3 values less than (30000)
6 ); Table created. SQL>
SQL> --
SQL> -- all partitions do NOT align, so we do NOT see partition-wise join
SQL> --
SQL>
SQL> insert into t2 select * from t1; 29999 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats('','t2') PL/SQL procedure successfully completed. SQL> set autotrace traceonly explain
SQL> select count(t1.y), count(t2.y)
2 from t1,t2
3 where t1.x = t2.x; Execution Plan
----------------------------------------------------------
Plan hash value: 666786458 ---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 1369 (1)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 20 | | | | |
|* 2 | HASH JOIN | | 29999 | 585K| 1369 (1)| 00:00:01 | | |
| 3 | PART JOIN FILTER CREATE | :BF0000 | 29999 | 585K| 1369 (1)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 29999 | 292K| 820 (1)| 00:00:01 | 1 | 3 |
| 5 | TABLE ACCESS FULL | T1 | 29999 | 292K| 820 (1)| 00:00:01 | 1 | 3 |
| 6 | PARTITION RANGE JOIN-FILTER| | 29999 | 292K| 548 (1)| 00:00:01 |:BF0000|:BF0000|
| 7 | TABLE ACCESS FULL | T2 | 29999 | 292K| 548 (1)| 00:00:01 |:BF0000|:BF0000|
--------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("T1"."X"="T2"."X") Note
-----
- this is an adaptive plan SQL> set autotrace off
SQL>
SQL>

这里的关键元素是散列连接现在位于所有分区的循环之上。在Oracle的早期版本中,你不会看到包含:BF0000的行,因此这是一个跨所有行的简单联接,就好像这些表根本没有分区一样。但是当分区不一致时,在现代版本中情况会稍微好一些。我们使用“Bloom filter”(因此:BF前缀)来减少连接两个表的开销。既然我在这篇文章中使用了比喻,那就想想“提前打电话”到电影院,看看有没有你最喜欢的电影的座位。如果电影院老板说电影已经卖完了,你就省了一趟车。但只是因为影院老板说还有空座,你还是有可能开车去那里,发现电影在那段时间已经卖完了。“Bloom filter”就像提前打电话一样——你很有可能可以避免一些工作,但这并不是一个保证。你可以在Christian Antognini的一篇伟大的白皮书中读到有关“Bloom filter”的内容。

注意,所有的分区必须对齐。下面是一个示例,其中前三个分区是对齐的,边界是10000、20000和30000,但是第二个表T2定义了一个额外的分区。再一次,我们回到了Bloom filter选项。

SQL> --
SQL> -- Example 3
SQL> --
SQL> drop table t2 purge; Table dropped. SQL> create table t2 ( x int, y int )
2 partition by range ( x )
3 (
4 partition p1 values less than (10000),
5 partition p2 values less than (20000),
6 partition p3 values less than (30000),
7 partition p4 values less than (40000)
8 ); Table created. SQL>
SQL> --
SQL> -- all partitions do NOT align, so we do NOT see partition-wise join
SQL> --
SQL>
SQL> insert into t2 select rownum, rownum from dual connect by level < 40000; 39999 rows created. SQL> commit; Commit complete. SQL> exec dbms_stats.gather_table_stats('','t2') PL/SQL procedure successfully completed. SQL> set autotrace traceonly explain
SQL> select count(t1.y), count(t2.y)
2 from t1,t2
3 where t1.x = t2.x; Execution Plan
----------------------------------------------------------
Plan hash value: 666786458 ---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 1913 (1)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 20 | | | | |
|* 2 | HASH JOIN | | 29999 | 585K| 1913 (1)| 00:00:01 | | |
| 3 | PART JOIN FILTER CREATE | :BF0000 | 29999 | 585K| 1913 (1)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 29999 | 292K| 820 (1)| 00:00:01 | 1 | 3 |
| 5 | TABLE ACCESS FULL | T1 | 29999 | 292K| 820 (1)| 00:00:01 | 1 | 3 |
| 6 | PARTITION RANGE JOIN-FILTER| | 39999 | 390K| 1093 (1)| 00:00:01 |:BF0000|:BF0000|
| 7 | TABLE ACCESS FULL | T2 | 39999 | 390K| 1093 (1)| 00:00:01 |:BF0000|:BF0000|
--------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("T1"."X"="T2"."X") Note
-----
- this is an adaptive plan SQL> set autotrace off
SQL>
SQL>
SQL>

因此,对分区表进行更快的查询不仅仅是关于分区修剪。Partition-wise joins还可以对查询响应时间产生有益的影响。

https://connor-mcdonald.com/2017/09/21/partition-wise-join/

Partition-wise join的更多相关文章

  1. Oracle Partition Outer Join 稠化报表

    partition outer join实现将稀疏数据转为稠密数据,举例: with t as (select deptno, job, sum(sal) sum_sal from emp group ...

  2. oracle已知会导致错误结果的bug列表(Bug Issues Known to cause Wrong Results)

    LAST UPDATE:     1 Dec 15, 2016 APPLIES TO:     1 2 3 4 Oracle Database - Enterprise Edition - Versi ...

  3. 【原创】大数据基础之Spark(8)Spark中Join实现原理

    spark中join有两种,一种是RDD的join,一种是sql中的join,分别来看: 1 RDD join org.apache.spark.rdd.PairRDDFunctions /** * ...

  4. 009-Hadoop Hive sql语法详解4-DQL 操作:数据查询SQL-select、join、union、udtf

    一.基本的Select 操作 语法SELECT [ALL | DISTINCT] select_expr, select_expr, ...FROM table_reference[WHERE whe ...

  5. CMU Database Systems - Sorting,Aggregation,Join

    Sorting 排序如果可在内存里面排,用经典的排序算法就ok,比如快排 问题在于,数据表中的的数据是很多的,没法一下都放到内存里面进行排序 所以就需要用到,外排,多路并归排序 看下最简单的,2路并归 ...

  6. Hash Join: Basic Steps

    Joins https://docs.oracle.com/database/121/TGSQL/tgsql_join.htm#TGSQL242 tidb/index_lookup_hash_join ...

  7. 柯南君 :Oracle 分区技术 之 怎样支撑大数据操作?

    前段时间.看了罗女士( 资深技术顾问 - Oracle 中国 顾问咨询部)关于<大批量数据处理技术的演讲>视频.感觉受益良多,结合多年的知识积累,柯南君给大家分享一下: 交流内容: 一.O ...

  8. Oracle12c版本中未归档隐藏参数

    In this post, I will give a list of all undocumented parameters in Oracle 12.1.0.1c. Here is a query ...

  9. Oracle11g版本中未归档隐藏参数

    In this post, I will give a list of all undocumented parameters in Oracle 11g. Here is a query to se ...

  10. Spark RDD概念学习系列之RDD的依赖关系(宽依赖和窄依赖)(三)

    RDD的依赖关系?   RDD和它依赖的parent RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency). 1)窄依赖指的是每 ...

随机推荐

  1. Java部分目录

    一.Java基础 1.访问权限控制 2.重载和覆盖 3.面向对象的特征 4.接口和抽象类 5.Java环境变量配置 6.Java英文缩写详解 7.如何在Maven项目中引入自己的jar包 8.使用ba ...

  2. php和mysql交互 面向对象

    不返回结果集 <?php //使用对象属性和方法来插入数据 header('Content-type:text/html;carset=utf8'); $con=new mysqli('loca ...

  3. (二)分布式数据库tidb-事务

    tidb既然是分布式数据库,所以它的事务应该可其它数据库事务有着不同的区别.我们来了解下tidb的数据库事务. (一)事物 1.几种数据库的默认隔离级别: tidb是乐观锁 (二)事务语句 TiDB ...

  4. webapi之owin的oauth2.0密码模式_01概述

    一般在webapi接口中,为了防止接口被随意调用,都会验证用户身份. 然而不能每次调用接口都需要用户输入用户名密码来验证,这时就需要授权颁发令牌了,持有令牌就可以访问接口,接口也能验证令牌身份. 简单 ...

  5. 【统计难题】【HDU - 1251】【map打表或字典树】【字典树模板】

    思路 题意:题目为中文题,这里不再过多阐述. 思路1:可以在读入单词表的过程中将单词分解,用map将它一 一记录 思路2:利用字典树,这个方法较快些,下面代码中会分别给出数组和结构体指针两种形式的字典 ...

  6. Kotlin属性引用详解

    继续来学习Kotlin反射相关的,这次主要是跟反射属性相关的东东. 属性引用(Property Reference): 属性引用的用法与函数(方法)引用的用法是完全一致,都是通过::形式来引用的.下面 ...

  7. http消息与webservice

    别人的:在一台配置较低的PC上,同时开启服务端与客户端,10000条数据,使用基于http的消息逐条进行传递,从开始传递至全部接收并处理完毕,大概需要465秒的时间:而在同一台机器上,使用WebSer ...

  8. 关于git clone远程仓库账户密码错误的问题

    这两天刚使用coding和git,但是在我第一次克隆coding上的项目的时候,提示输入账户和密码,当时我不知道这个账户和密码是指的哪个,就随便输入了,然后提示错误,,,,,, 之后每次克隆的时候都提 ...

  9. MySQL命令操作(Linux平台)

    Linux shell 批量创建数据库/表 Shell 脚本如下: # create database and table HOST='localhost' PORT='3306' USER='roo ...

  10. Import declarations are not supported by current JavaScript version

    原因为:不支持当前的js版本,在perference中进行设置javascript的版本即可 注意:在perference中进行更改,而不是defeaut perference,快捷键操作为:comm ...