<article class=“article fmt article-content”><h2>背景</h2><p>最近在浏览查问优化器的论文,发现<strong>System R</strong>中对于Join操作的定义个别分为了两种,即嵌套循环、排序-合并联接。在原文中,更偏向应用排序-合并联接逻辑。</p><p>思考到我的畛域是在解决分库分表或者其余的分区模式,这让我开始不由得联想咱们怎么在分布式场景利用这个Join逻辑,对于两个不同库外面的不同表咱们是没有方法间接进行Join操作的。查阅材料后发现原来早有定义,即分布式联接算法。</p><h2>分布式联接算法</h2><p>跨界点解决数据即分布式联接算法,常见的有四种模型:Shuffle Join(洗牌联接)、Broadcast Join(播送联接)、MapReduce Join(MapReduce联接)、Sort-Merge Join(排序-合并联接)。</p><p>接下来将进行逐个理解与剖析,以便后续开发的利用。</p><h3>Shuffle Join(洗牌联接)</h3><p>先上原理解释:</p><blockquote>Shuffle Join的核心思想是将来自不同节点的数据从新散发(洗牌),使得能够联接的数据行最终位于同一个节点上。 通常,对于要联接的两个表,会对联接键利用雷同的哈希函数,哈希函数的后果决定了数据行应该被发送到哪个节点。这样,所有具备雷同哈希值的行都会被送到同一个节点,而后在该节点上执行联接操作。</blockquote><p>可能解释完还是有点含糊,举个例子,有两张表,别离以id字段进行分库操作,且哈希算法雷同(为了简略,这里只介绍分库场景,分库分表同理。算法有很多种,这里举例是hash算法),那么这两张表的分片或者能够在同一个物理库中,这样咱们不须要做大表维度的解决,咱们能够间接下推Join操作到对应的物理库操作即可。</p><p>在ShardingSphere中,这种场景相似于绑定表的定义,如果两张表的算法雷同,能够间接配置绑定表的关系,进行雷同算法的连贯查问,防止简单的笛卡尔积。</p><p>这样做的益处是能够尽量下推到数据库操作,在中间件层面咱们能够做并行处理,适宜大规模的数据操作。</p><p>然而,这很现实,有多少表会采纳雷同算法解决呢。</p><h3>Broadcast Join(播送联接)</h3><p>先上原理解释:</p><blockquote>当一个表的大小绝对较小时,能够将这个小表的全副数据播送到所有蕴含另一个表数据的节点上。 每个节点上都有小表的残缺正本,因而能够独立地与本地的大表数据进行联接操作,而不须要跨节点通信。</blockquote><p>举个例子,有一张十分小的表A,还有一张依照ID分片的表B,咱们能够在每一个物理库中复制一份表A,这样咱们的Join操作就能够间接下推到每一个数据库操作了。</p><p>这种状况比Shuffle Join甚至还有性能高效,这种相似于ShardingSphere中的播送表的定义,其存在相似于字典表,在每一个数据库都同时存在一份,每次写入会同步到多个节点。</p><p>这种操作的益处不言而喻,不仅反对并行操作而且性能极佳。</p><p>然而毛病也不言而喻,如果小表不够小数据冗余不说,播送可能会耗费大量的网络带宽和资源。</p><h3>MapReduce Join(MapReduce联接)</h3><p>先上原理解释:</p><blockquote>MapReduce是一种编程模型,用于解决和生成大数据集,其中的联接操作能够分为两个阶段:Map阶段和Reduce阶段。 Map阶段:每个节点读取其数据分片,并对须要联接的键值对利用一个映射函数,生成两头键值对。 Reduce阶段: 两头键值对会依据键进行排序(在某些实现中排序产生在Shuffle阶段)和分组,而后发送到Reduce节点。 在Reduce节点上,具备雷同键的所有值都会汇集在一起,这时就能够执行联接操作。</blockquote><p>MapReduce Join不间接利用于传统数据库逻辑,而是实用于Hadoop这样的分布式解决零碎中。然而为了不便了解,还是用SQL语言来剖析,例如一条SQL:</p><pre><code>SELECT orders.order_id, orders.date, customers.nameFROM ordersJOIN customers ON orders.customer_id = customers.customer_id;</code></pre><p>会被转换为两个SQL:</p><pre><code>SELECT customer_id, order_id, date FROM orders;SELECT customer_id, name FROM customers;</code></pre><p>这个过程就是Map阶段,即读取<code>orders</code>和<code>customers</code>表的数据,并为每条记录输入键值对,键是<code>customer_id</code>,值是记录的其余部分。</p><p>下一个阶段可有可无,即Shuffle阶段。如果不在这里排序可能会在Map阶段执行SQL时候排序/分组或者在接下来的Reduce阶段进行额定排序/分组。在这个阶段次要将收集到的数据依照customer_id排序分组,以确保雷同的customer_id的数据达到Reduce阶段。</p><p>Reduce阶段将每个对应的customer_id进行联接操作,输入并返回最初的后果。</p><p>这种操作广泛利用于两个算法齐全不雷同的表单,也是一种规范的解决模型,在这个过程中,咱们以一张逻辑表的维度进行操作。这种算法可能会耗费大量内存,甚至导致内存溢出,并且在解决大数据量时会相当耗时,因而不适宜须要低提早的场景。</p><h4>额定补充</h4><p>内存溢出场景广泛在如下场景:</p><p>1.大键值对数量:如果Map阶段产生了大量的键值对,这些数据须要在内存中进行缓存以进行排序和传输,这可能会耗费大量内存。</p><p>2.数据歪斜:如果某个键十分常见,而其余键则不那么常见,那么解决这个键的Reducer可能会接管到大量的数据,导致内存不足。这种景象称为数据歪斜。</p><p>3.大值列表:在Reduce阶段,如果某个键对应的值列表十分长,解决这些值可能会须要很多内存。</p><p>4.不合理的并行度:如果Reduce工作的数量设置得不适合(太少或太多),可能会导致单个工作解决不平均,从而导致内存问题。</p><p>我能想到的相应解决方案:</p><p>•内存到磁盘的溢写:当Map工作的输入缓冲区满了,它会将数据溢写到磁盘。这有助于限度内存应用,但会减少I/O开销。</p><p>•通过设置适合的Map和Reduce工作数量,能够更无效地分配资源,防止某些工作过载。具体操作能够将Map操作的分段比方1~100,100~200,Reduce阶段开设较少的并发解决。</p><p>•优化数据分布,比方应用范畴分区(range partitioning)或哈希分区(hash partitioning)来缩小数据歪斜。</p><h3>Sort-Merge Join(排序-合并联接)</h3><p>先上原理解释:</p><blockquote>在分布式环境中,Sort-Merge Join首先在每个节点上对数据进行部分排序,而后将排序后的数据合并起来,最初在合并的数据上执行联接操作。 这通常波及到多阶段解决,包含部分排序、数据洗牌(从新散发),以及最终的排序和合并。</blockquote><p>举个了解,还是下面的SQL。</p><pre><code>SELECT orders.order_id, orders.date, customers.nameFROM ordersJOIN customers ON orders.customer_id = customers.customer_id;</code></pre><p>1.对<code>orders</code>表按<code>customer_id</code>进行排序。</p><p>2.对<code>customers</code>表按<code>customer_id</code>进行排序。</p><p>3.同时遍历两个已排序的表,将具备雷同<code>customer_id</code>的行配对。</p><p>这个就有点相似于原生的排序-合并联接了。也是数据库场景的规范解决方法。</p><p>对于曾经排序的数据集或数据分布平均的状况,这种办法十分无效。如果数据未事后排序,这种办法可能会十分慢,因为它要求数据在联接之前进行排序。</p><p>当然,这个算法也会造成内存溢出的场景,解决方案如下:</p><p>1.当数据集太大而无奈一次性加载到内存中时,能够应用内部排序算法。内部排序算法会将数据宰割成多个批次,每个批次独自排序,而后将排序后的批次合并。这种办法通常波及到磁盘I/O操作,因而会比内存中操作慢。</p><p>2.对于合并步骤,能够应用流式解决技术,一次只解决数据的一小部分,并继续将后果输入到下一个解决步骤或存储系统。这样能够防止一次性加载大量数据到内存中。</p><p>3.当内存不足以解决数据时,能够应用磁盘空间作为长期存储。数据库管理系统通常有机制来解决内存溢出,比方创立磁盘上的临时文件来存储过程中的数据。</p><p>4.在分布式系统中,能够将数据扩散到多个节点上进行解决,这样每个节点只须要解决数据的一部分,从而缩小单个节点上的内存压力。</p><p>作者:京东科技 张豪杰</p><p>起源:京东云开发者社区 转载请注明起源</p></article>