Partition-wise join
什么是“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的更多相关文章
- Oracle Partition Outer Join 稠化报表
partition outer join实现将稀疏数据转为稠密数据,举例: with t as (select deptno, job, sum(sal) sum_sal from emp group ...
- 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 ...
- 【原创】大数据基础之Spark(8)Spark中Join实现原理
spark中join有两种,一种是RDD的join,一种是sql中的join,分别来看: 1 RDD join org.apache.spark.rdd.PairRDDFunctions /** * ...
- 009-Hadoop Hive sql语法详解4-DQL 操作:数据查询SQL-select、join、union、udtf
一.基本的Select 操作 语法SELECT [ALL | DISTINCT] select_expr, select_expr, ...FROM table_reference[WHERE whe ...
- CMU Database Systems - Sorting,Aggregation,Join
Sorting 排序如果可在内存里面排,用经典的排序算法就ok,比如快排 问题在于,数据表中的的数据是很多的,没法一下都放到内存里面进行排序 所以就需要用到,外排,多路并归排序 看下最简单的,2路并归 ...
- Hash Join: Basic Steps
Joins https://docs.oracle.com/database/121/TGSQL/tgsql_join.htm#TGSQL242 tidb/index_lookup_hash_join ...
- 柯南君 :Oracle 分区技术 之 怎样支撑大数据操作?
前段时间.看了罗女士( 资深技术顾问 - Oracle 中国 顾问咨询部)关于<大批量数据处理技术的演讲>视频.感觉受益良多,结合多年的知识积累,柯南君给大家分享一下: 交流内容: 一.O ...
- Oracle12c版本中未归档隐藏参数
In this post, I will give a list of all undocumented parameters in Oracle 12.1.0.1c. Here is a query ...
- Oracle11g版本中未归档隐藏参数
In this post, I will give a list of all undocumented parameters in Oracle 11g. Here is a query to se ...
- Spark RDD概念学习系列之RDD的依赖关系(宽依赖和窄依赖)(三)
RDD的依赖关系? RDD和它依赖的parent RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency). 1)窄依赖指的是每 ...
随机推荐
- JavaScript笔记01_基本操作
目录 1. JS代码编写的位置 2. 为什么JavaScript中代码要以分号结束 3. 字面量和变量 4. 数据类型 5. 类型装换 6. ++a和a++ 7. 逻辑运算符 8. 相等运算符 9. ...
- Gtest:死亡测试
转自:玩转Google开源C++单元测试框架Google Test系列(gtest)之五 - 死亡测试 一.前言 “死亡测试”名字比较恐怖,这里的“死亡”指的的是程序的崩溃.通常在测试过程中,我们需要 ...
- PAT甲级1010踩坑记录(二分查找)——10测试点未过待更新
题目分析: 首先这题有很多的坑点,我在写完之后依旧还有第10个测试点没有通过,而且代码写的不优美比较冗长勿喷,本篇博客用于记录写这道题的一些注意点 1.关于两个不同进制的数比大小一般采用将两个数都转化 ...
- DT图库列表修改内容标题字数
dt限制标题字数的方法有几种,最简单的是一种是: {dsubstr($t[title], 42, '..')} 还有一种是列表输出,也是网上常用的方法 <!--{tag("module ...
- git添加doc文件维护
原文地址:https://www.cnblogs.com/yezuhui/p/6853271.html 说明: git 一般只能对纯文本文件进行版本控制,但是如果有其他中间转化软件的协助,就可以对任意 ...
- Linux——CentOS7没有ifconfig命令
前言 今天新安装的centos7,使用ifconfig命令却提示没有,直接安装也没有~ 正文 直接安装直接告诉我这个包不是一个有效的 [root@kafka ~]# yum install -y if ...
- 趣味编程:FizzBuzz(Haskell版)
g :: Int -> Int -> Int -> String g n 0 0 = "FizzBuzz" g n 0 _ = "Fizz" ...
- 分析第一个Android程序
项目结构切换Project, 项目真实目录结构 { 1. .gradle和idea 两个目录放置的都是Android Studio 自动生成的一些文件,我们无需关心,也不要去手动编辑. 2.AP ...
- robot framework的使用方法
1.后台代码: 目录结构: 测试代码:Arithmetic.py 2.开始编写用例 直接在eclipse上新建一个txt文件即可,或者是通过ride编写用例. (1).首先在eclipse上新建目录T ...
- junit4的进一步探讨
上次只是大概记录了下junit4几个常见标签的用法. 在这篇文章中,我们来进一步分析junit4的用法. 1.断言 junit4中一个很常见的用法就是断言.说到断言,大家再熟悉不过了.不过也许有的朋友 ...