diff --git a/content/zh-cn/blog/20220426/01.jpg b/content/zh-cn/blog/20220426/01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0b25e5e26f2e7c9df171894af56a748514e1bdff Binary files /dev/null and b/content/zh-cn/blog/20220426/01.jpg differ diff --git a/content/zh-cn/blog/20220426/02.jpg b/content/zh-cn/blog/20220426/02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7b5d7aadb279b608681fb8b984bb2610cd7d2b0 Binary files /dev/null and b/content/zh-cn/blog/20220426/02.jpg differ diff --git a/content/zh-cn/blog/20220426/03.jpg b/content/zh-cn/blog/20220426/03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4e9ba52e58b702690660ac207072c32607bb405 Binary files /dev/null and b/content/zh-cn/blog/20220426/03.jpg differ diff --git a/content/zh-cn/blog/20220426/04.jpg b/content/zh-cn/blog/20220426/04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8248a9049eac85779ac5a1c6655521bcad1ac90c Binary files /dev/null and b/content/zh-cn/blog/20220426/04.jpg differ diff --git a/content/zh-cn/blog/20220426/05.png b/content/zh-cn/blog/20220426/05.png new file mode 100644 index 0000000000000000000000000000000000000000..693591ff924e3f35c40519cf6317ca391391ebe5 Binary files /dev/null and b/content/zh-cn/blog/20220426/05.png differ diff --git a/content/zh-cn/blog/20220426/20220426.md b/content/zh-cn/blog/20220426/20220426.md new file mode 100644 index 0000000000000000000000000000000000000000..e4060248f45de9bbfcd1510330f3c17196974daf --- /dev/null +++ b/content/zh-cn/blog/20220426/20220426.md @@ -0,0 +1,74 @@ ++++ +title = "CTE测试报告" +date = "2022-04-26" +tags = [ "openLooKeng", "CTE"] +archives = "2022-04" +author = "支海东" +description = "CTE(Common Table Expression) Reuse是一种能够专门存放临时查询结果,从而减小反复查询带来的硬件开销的机制。在openLooKeng中,我们为了提高数据库整体的运行效率,广泛地采用了这种机制。" ++++ + +##

1 概述

+ +CTE(Common Table Expression) Reuse是一种能够专门存放临时查询结果,从而减小反复查询带来的硬件开销的机制。在openLooKeng中,我们为了提高数据库整体的运行效率,广泛地采用了这种机制。 + +### 1.1 背景 + +在编写SQL语句时,很多时候,我们想选取一段数据,为了之后使用的便捷性,会为其取名。形如WITH … AS (SELECT … FROM …)。 +例如,在如下程序(这段代码即是Q95.sql)中,我们在程序刚开始的时候就声明了“ws_wh”的具体内容,并在声明后3次用到了这部分数据,如图所示。 + + + +然而,SQL中用WITH … AS …所声明的SQL表达式并不是C/C++/java/python中所声明的变量。后者在每次被使用的时候可以直接调用,但前者即便被声明了,在之后被使用的时候仍然需要重新用具体的语句去选取并计算相应的数据。这就消耗了极大的机器资源。至此,我们便很容易思考一个问题,能否将被声明的SQL表达式存储在一个“表格”中以避免反复查询和生成,从而极大地节约运算资源,提高运算效率? + +### 1.2 原理 + +CTE机制就是为了解决上述问题,应运而生的。当第一次声明某个SQL表达式作为临时表时,我们将该SQL表达式从硬盘读取、计算并储存至缓存,此时这张表被称为“生产者”(producer);而当这张表被反复从缓存中读取以便使用时,我们称其为“消费者”(consumer)。由于消费者是被储存在缓存中的,我们不需要反复生成“生产者”。而从缓存读取数据又比从硬盘读取要快,且不需要二次计算,这样同一段SQL代码,在有了CTE机制后,执行速度会大大提高。比如,下图中,若不开起CTE机制,同一个SQL表达式在声明后仍需要被反复生成。但开启了CTE机制,从计算流程图上,我们都能很轻易地看出流程被大大简化。 + + + +用户执行一段启动了CTE机制的SQL代码的流程图如下图所示。首先解析是否存在相似的子查询,若存在,则将其查询结果储存在外部的缓存中以便之后使用。 + + + +##

2 测试

+ +为了审视CTE机制开启后的具体效果,我们进行一个测试:对同样的几个节点在先不开启后开启CTE机制的状态下,测试同样的几段SQL代码在相同节点上的运行时间。最终通过运行时间的变化体现执行效率的变化。 + +### 2.1 环境配置 + + + + + + + +以上3个网页已经详细讲述了如何配置协调节点(Coordinator Node)和工作节点(Worker Node),而是否开启CTE机制,取决于是否在/etc/config.properties这个文件中加入语句: + +```java +optimizer.cte-reuse-enabled=true +``` + +### 2.2 测试结果 + +在看具体数字前,我们首先看看计算图的变化。 + + + +这两张图分别是CTE机制开启前后,在同样的节点上运行同样的程序(Q95.sql)的计算图。可见,就像原理部分中所叙述的那样,计算图本身已经被简化。左图中标红的两段SQL语句,在右图中,已经被CTE Reuse机制“融合”成了一个部分,精简了计算流程。 +最后,这张表是5段不同的代码在CTE机制开启前后的运行效率对比。 + 不开CTE运行时间(s) 开启CTE运行时间(s) + + + +--- + +如果您有任何疑问或建议,欢迎在社区代码仓内提Issue;也欢迎加小助手微信(openLooKengoss),进入专属技术交流群。 + +社区代码仓 + + + + + + +openLooKeng,让大数据更简单! \ No newline at end of file diff --git a/content/zh-cn/blog/20220427/01.jpg b/content/zh-cn/blog/20220427/01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f78bae4cad141ddab0933a1e851acf43e405eb7 Binary files /dev/null and b/content/zh-cn/blog/20220427/01.jpg differ diff --git a/content/zh-cn/blog/20220427/02.jpg b/content/zh-cn/blog/20220427/02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a6feb4b742315a25a340be0d08a9a732980e1792 Binary files /dev/null and b/content/zh-cn/blog/20220427/02.jpg differ diff --git a/content/zh-cn/blog/20220427/03.jpg b/content/zh-cn/blog/20220427/03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bdd8ba856eaac37abc43f4406dc5ddcfb81acdc1 Binary files /dev/null and b/content/zh-cn/blog/20220427/03.jpg differ diff --git a/content/zh-cn/blog/20220427/04.jpg b/content/zh-cn/blog/20220427/04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4b634c9449a8d62e1519a5bb9ef477c2e70366b Binary files /dev/null and b/content/zh-cn/blog/20220427/04.jpg differ diff --git a/content/zh-cn/blog/20220427/05.jpg b/content/zh-cn/blog/20220427/05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b5449ec4fc96c45c624beb0bae434b13f2d1537 Binary files /dev/null and b/content/zh-cn/blog/20220427/05.jpg differ diff --git a/content/zh-cn/blog/20220427/06.jpg b/content/zh-cn/blog/20220427/06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2d65858c815590d5d3d03bb5574130842e73f3ba Binary files /dev/null and b/content/zh-cn/blog/20220427/06.jpg differ diff --git a/content/zh-cn/blog/20220427/07.png b/content/zh-cn/blog/20220427/07.png new file mode 100644 index 0000000000000000000000000000000000000000..6f9ecb14a443aef3b484243cc1c85d44c84934e1 Binary files /dev/null and b/content/zh-cn/blog/20220427/07.png differ diff --git a/content/zh-cn/blog/20220427/20220427.md b/content/zh-cn/blog/20220427/20220427.md new file mode 100644 index 0000000000000000000000000000000000000000..dddf463ad0c1ee24e738da52e9a75a511c693469 --- /dev/null +++ b/content/zh-cn/blog/20220427/20220427.md @@ -0,0 +1,90 @@ ++++ +title = "动态过滤测试报告" +date = "2022-04-27" +tags = [ "openLooKeng", "动态过滤"] +archives = "2022-04" +author = "支海东" +description = "Join在SQL语言中,是数据库查询永远绕不开的话题,也是SQL中最为复杂,代价最大的操作类型。而在hash join中,如何使构建端(build –side)和探测端(probe-scan)高效运行,便成为了需要研究的问题。动态过滤(Dynamic Filtering)就是为了解决这个问题而应运而生的机制。在openLooKeng中,我们广泛地采用了这种机制。" ++++ + +##

1 概述

+ +Join在SQL语言中,是数据库查询永远绕不开的话题,也是SQL中最为复杂,代价最大的操作类型。而在hash join中,如何使构建端(build –side)和探测端(probe-scan)高效运行,便成为了需要研究的问题。动态过滤(Dynamic Filtering)就是为了解决这个问题而应运而生的机制。在openLooKeng中,我们广泛地采用了这种机制。 + +### 1.1 背景 + +SQL语言中join大致有几种执行机制。最简单的是Nested-Loop join和Blocked Nested-Loop join。假设现在有两张表R和S, Nested-Loop join会用二重循环的方式扫描每个(r,s)对,若符合join的条件,就匹配成功,其时间复杂度也很简单地可推导为O(|R||S|)。而Blocked Nested-Loop join是基于前者的改进版,其思路是对于外层循环的表R,不再逐行扫描,而是一次加载一批(即所谓Block)数据进入内存,并且将它们按join key散列在哈希表里,然后也按批扫描表S,并与哈希表进行比对,能够对的上的行就作为join的输出。一个block数据的大小一般是一个或多个内存页的容量。这样就可以将I/O复杂度从O(|R||S|)降低到O[p(R) * p(S) / M],其中p(R)、p(S)分别代表R和S换算成页数的大小,M代表可用内存中的总页数。 + +此二种loop join的原理图如下所示: + + + +除此以外,主要是Hash join和Grace Hash join。Sort-Merge join由于和动态过滤并不相关,本文在此不予以讨论。Hash join分为两个阶段,构建(build)和探测(probe)。我们将join两端中较小的那个集合R作为构建集(build set),另一个S作为探测集(probe set)。在构建阶段,我们将R的所有数据按照主键进行哈希散列,构成一张哈希表,而哈希表的值便是R原来的行数据。而在探测阶段,我们扫描探测集S,取得S的主键的哈希值并判断其是否在哈希表之中,输出结果。此二阶段的过程的示意图如下所示。易知,其时间复杂度为O(|R|+|S|)。 + + + +而Grace Hash join的原理,只是改进版,并不影响我们对于动态过滤机制的理解,因而在此处略去不表。 + +### 1.2 原理 + +上文中已经介绍了join本身的原理,接下来我们介绍动态过滤。 +在筛选机制比较苛刻的场景中,绝大多数探测端的行是一经筛选,不匹配则直接丢弃的。但如果我们将这个谓词从计划阶段下沉到执行阶段,在构建端已经有严格筛选条件的情况下,直接减少构建集的计算,从而不去读取探测端那些不匹配的行而不是先读取再丢弃,就节约了大量的筛选时间,极大地提高了运行效率。而这个过程,就叫做动态过滤。 + + + +如上图所示,item作为一个已经被严格筛选过的构建集,我们用过滤器F将筛选机制直接传递给探测集。如此,探测端的工作效率便会提升。而动态过滤机制的主要难点就在于如何把构建端的值从inner-join操作符传递到探测端,因为操作符很可能是在不同的机器上运行的。 +而在实施的时候,我们主要依靠“基于代价的优化器”(CBO, cost-based optimizer),这个优化器让我们可以使用“广播合并”(broadcast join)。在我们的案例中,构建端远小于探测端,探测端的扫描和inner-join操作符运行在同一进程中,这样信息的通信机制会容易很多。 +在确保了广播合并被使用且构建端的信息也能被传送到探测端的时候,我们加入“收集操作符”(collection operator),就放在哈希构建操作符之前。 + + + +如图,收集操作符收集了构建端的值,而当构建端的值输入完毕后,我们将动态过滤机制放到探测端一边。由于探测端的哈希映射和收集操作符的哈希映射是并行执行的,这里并不需要花费多余的时间。然后哈希匹配的时候,探测端就可以直接去被筛选过后的构建端的哈希表进行查找。 + +##

2 测试

+ +为了审视动态机制开启后的具体效果,我们进行一个测试:对同样的几个节点在先不开启后开启动态过滤机制的状态下,测试同样的几段SQL代码在相同节点上的运行时间。最终通过运行时间的变化体现执行效率的变化。值得一提的是,工作节点(worker nodes)的数量尽可能要大于1个。 + +### 2.1 环境配置 + + + + + + + +以上3个网页已经详细讲述了如何配置协调节点(Coordinator Node)和工作节点(Worker Node),以及是否开启动态过滤机制。需要注意的是,等待动态过滤条件生成的最长等待时间最好加上,并且设置为2s,即在etc/config.properties里加入语句 + +```java + +Dynamic-filtering-wait-time=2s + +``` + +否则有些SQL语句可能会出现由于等待时间不合适而并未开启动态过滤机制的情况。 + +### 2.2 测试结果 + +在看具体数字前,我们首先看看计算图的变化。 + + + + + +这两张图分别是动态过滤机制开启前后,在同样的节点上运行同样的程序的计算图。可见,就像原理部分中所叙述的那样,计算图中出现了动态过滤机制,右图中标红的SQL语句就是体现。 + +最后,这张表是6段不同的代码在动态过滤机制开启前后的运行效率对比。 + + + +--- + +如果您有任何疑问或建议,欢迎在社区代码仓内提Issue;也欢迎加小助手微信(openLooKengoss),进入专属技术交流群。 + +社区代码仓 + + + + + + +openLooKeng,让大数据更简单! \ No newline at end of file