欢迎来到皮皮网网首页

【金优外卖源码】【喜牛网站源码】【olap druid源码分析】hive 源码 distinct

来源:hbase源码多少行 时间:2024-12-28 18:14:54

1.hive的源码distinct与groupby的区别是什么?
2.开发实战角度:distinct实现原理及具体优化总结
3.Hive常用算子实现原理简述--MapReduce版
4.HIVE-SQL优化(持续更新ing)
5.Hive优化的原则参考
6.通过深挖Clickhouse源码,我精通了数据去重!源码

hive 源码 distinct

hive的源码distinct与groupby的区别是什么?

       理解Hive中的DISTINCT与GROUP BY功能,需从它们各自的源码核心作用入手。DISTINCT功能旨在去除结果集中的源码重复行,确保返回的源码金优外卖源码数据集不包含任何重复记录。具体而言,源码Hive在处理时,源码若未明确指定ALL或DISTINCT选项,源码则默认返回所有匹配行,源码而DISTINCT选项则确保结果集中只包含唯一行,源码多余重复的源码记录被去除。

       相比之下,源码GROUP BY操作则侧重于数据的源码分组与聚合。其本质是源码对数据进行逻辑上的分组处理,然后基于每个分组返回计算结果。数据处理的顺序是先进行分组操作,根据指定的字段将数据划分为不同的组,之后对每组数据执行聚合操作,如计算每组的总和、平均值等。这一过程充分体现了Hive在数据处理上的高效与灵活性。

       在理解了它们的基本逻辑与实现方式后,我们可以得出,尽管DISTINCT与GROUP BY在表面功能上存在差异,但在实际应用中,它们的性能表现可能较为相近。Hive优化器通常会将DISTINCT操作转换为GROUP BY操作,以更高效地利用并行计算资源。喜牛网站源码因此,选择使用DISTINCT还是GROUP BY,应基于个人习惯与具体需求,不必过于纠结。

       以具体的例子说明,当我们使用Hive执行SQL时,优化器可能自动将带有DISTINCT的查询转换为使用GROUP BY的查询,如以下执行计划所示,使用了Group By Operator。这一转换体现了Hive在优化过程中,为提高执行效率而采取的策略。

开发实战角度:distinct实现原理及具体优化总结

       Distinct是一种在数据库SQL语言中至关重要的操作,尤其在Hive中,它通过MapReduce机制来实现。Distinct操作可以应用于单列或多列,其基本原理是对数据集按照指定列进行分组,去除每个分组内的重复值,最终合并成唯一值的结果集。

       在最近的一次学习过程中,有位伙伴在研究count distinct时遇到了难题。虽然对单个count distinct原理理解尚可,但面对多字段count distinct时,讲解起来就变得复杂。下面将为大家总结这方面的内容。

       在深入Distinct之前,先来了解一下group by操作的实现原理。group by操作适合与distinct紧密相关的聚合操作,因此,olap druid源码分析总结distinct之前,需要了解group by的具体实现。

       在map阶段,将group by后的字段组合作为key,如果是单个字段,则key为一个。group by之后要进行的聚合操作字段作为值,如count则值为1;若sum另一个字段,则value是该字段值。shuffle阶段,按照key的不同分发到不同的reducer。reduce阶段,如果是count则将相同key的值累加,如果是其他操作,则按需要的聚合操作得到结果。

       在map阶段如果出现数据倾斜,可以进行相应的处理,常见的方法有单独计算key、替换随机数等。针对group by的特殊方法有几种。

       Distinct单字段原理:当执行Distinct操作时,Hive将其转化为MapReduce作业,并按指定列进行分组。Map阶段,每个Mapper读取输入数据,将指定列作为输出的key,通过Shuffle过程将具有相同key的数据发送到同一个Reducer中。由于使用了distinct,云盘存储源码Map端的combine无法合并重复数据,因此必须将id作为Key输出,在Reduce阶段再进行消重。

       对于count(distinct)全聚合操作,即使设置了reduce task的具体个数,Hive最终也只会启动一个reducer。这导致所有map端传来的数据都在一个tasks中执行,唯一的Reduce Task需要处理大量的数据,这成为整个作业的IO和运算瓶颈。

       Distinct一个字段时,将group by的字段和distinct的字段组合作为map输出的key,value设置为1,同时将group by的字段定为分区键。这样就可以将GroupBy字段作为reduce的key,在reduce阶段利用mapreduce的排序,输入天然就是按照组合key排好序的。根据分区键将记录分发到reduce端后,按顺序取出组合键中的distinct字段,这时distinct字段也是排好序的。依次遍历distinct字段,每找到一个不同值,计数器就自增1,即可得到count distinct结果。

       对于单distinct的优化,可以通过将原来一个MapReduce作业转换为两个作业,在第一阶段选出全部的非重复的字段id,在第二阶段再对这些已消重的id进行计数。这样可以在第一阶段通过增大Reduce的梦幻西游易源码并发数来处理Map输出,在第二阶段,由于id已经消重,COUNT(*)操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。

       对于mult-distinct,如果按照上面一个distinct字段的方法,无法根据uid和date分别排序,也就无法通过LastKey去重,仍然需要在reduce阶段在内存中通过Hash去重。Hive会使用另一种处理方式,对所有的distinct字段编号,那么相同字段就会分别排序,这时只需要在reduce阶段记录LastKey即可去重。这种实现方式利用了MapReduce的排序,节省了reduce阶段去重的内存消耗,但缺点是增加了shuffle的数据量。

       对于多重distinct的操作,可以按照一定步骤进行优化。

Hive常用算子实现原理简述--MapReduce版

       Hive中的常用算子包括distinct、join、group by、order by、distribute by、sort by、count等,这些操作符在SQL中使用起来很方便,能快速达到我们想要的效果,但是这些算子在底层是怎么实现的呢?

        order by很容易想到执行原理,在一个reduce中将所有记录按值排序即可。因此order by在数据量大的情况下执行时间非常长,容易out of memory,非特殊业务需求一般不使用。distribute by也比较明显,根据hash值将distribute的值分发到不同的reduce。sort by是小号的order by,只负责将本reducer中的值排序,达到局部有序的效果。sort by和distribute by配合使用风味更佳,二者可以合并简写为cluster by。count则更加明晰,在combiner或reducer处按相同键累加值就能得到。

        比较复杂的是distinct、join、group by,本文重点讨论这三个算子在MapReduce引擎中的大致实现原理。班门弄斧,抛砖引玉。

        map阶段,将group by后的字段组合作为key,如果group by单字段那么key就一个。将group by之后要进行的聚合操作字段作为值,如要进行count,则value是1;如要sum另一个字段,则value就是该字段。

        shuffle阶段,按照key的不同分发到不同的reducer。注意此时可能因为key分布不均匀而出现数据倾斜的问题。

        reduce阶段,将相同key的值累加或作其他需要的聚合操作,得到结果。

        对group by的过程讲解的比较清楚的是这篇文章 /info-detail-.html 图文并茂,很生动。

        实例如下图,对应语句是 select rank, isonline, count(*) from city group by rank, isonline;

        如果group by出现数据倾斜,除去替换key为随机数、提前挑出大数量级key值等通用调优方法,适用于group by的特殊方法有以下几种:

        (1)set hive.map.aggr=true,即开启map端的combiner,减少传到reducer的数据量,同时需设置参数hive.groupby.mapaggr.checkinterval 规定在 map 端进行聚合操作的条目数目。

        (2)设置mapred.reduce.tasks为较大数量,降低每个reducer处理的数据量。

        (3)set hive.groupby.skewindata=true,该参数可自动进行负载均衡。生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group ByKey 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce中),最后完成最终的聚合操作。

        Hive中有两种join方式:map join和common join

        如果不显式指定map side join,或者没有达到触发自动map join的条件,那么会进行reduce端的join,即common join,这种join包含map、shuffle、reduce三个步骤。

        (1)Map阶段

        读取源表的数据,Map输出时候以Join on条件中的列为key,如果Join有多个关联键,则以这些关联键的组合作为key。Map输出的value为join之后所关心的(select或者where中需要用到的)列;同时在value中还会包含表的Tag信息,用于标明此value对应哪个表。然后按照key进行排序。

        (2)Shuffle阶段

        根据key的值进行hash,并将key/value按照hash值推送至不同的reduce中,这样确保两个表中相同的key位于同一个reduce中

        (3)Reduce阶段

        根据key的值完成join操作,期间通过Tag来识别不同表中的数据。

        以下面的SQL为例,可用下图所示过程大致表达其join原理。

        SELECT u.name, o.orderid FROM user u JOIN order o ON u.uid = o.uid;

        关联字段是uid,因此以uid为map阶段的输出key,value为选取的字段name和标记源表的tag。shuffle阶段将相同key的键值对发到一起,reduce阶段将不同源表、同一key值的记录拼接起来,可能存在一对多的情况。

        如果指定使用map join的方式,或者join的其中一张表小于某个体积(默认MB),则会使用map join来执行。具体小表有多小,由参数 hive.mapjoin.smalltable.filesize 来决定。

        Hive0.7之前,需要使用hint提示 /*+ mapjoin(table) */才会执行MapJoin,否则执行Common Join,但在0.7版本之后,默认自动会转换Map Join,由参数 hive.auto.convert.join 来控制,默认为true。

        以下图为例说明map join如何执行,该图来自 /archives///.htm ,博主是一个水平深厚又乐于分享的前辈,图片水印上也有其网址。

        yarn会启动一个Local Task(在客户端本地执行的Task)--Task A,负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中。

        接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。

        由于MapJoin没有Reduce,所以由Map直接输出结果文件,有多少个Map Task,就有多少个结果文件。

        distinct一般和group by同时出现。

        当distinct一个字段时,将group by的字段和distinct的字段组合在一起作为map输出的key,value设置为1,同时将group by的字段定为分区键,这可以确保相同group by字段的记录都分到同一个reducer,并且map的输入天然就是按照组合key排好序的。根据分区键将记录分发到reduce端后,按顺序取出组合键中的distinct字段,这时distinct字段也是排好序的。依次遍历distinct字段,每找到一个不同值,计数器就自增1,即可得到count distinct结果。例如下面的SQL语句,过程可以下图示意。

        我暂时没有理解这是怎么实现的,别人写的也没有看明白。有善良的学富五车的大佬指点一下吗?

HIVE-SQL优化(持续更新ing)

       优化HIVE SQL主要包括配置优化、SQL语句优化以及任务优化等方案。在开发过程中,主要关注SQL优化。优化的核心思想包括减少数据量、避免数据倾斜、避免全表扫描以及减少job数。

       在SQL优化中,关键点包括使用分区剪裁和列剪裁以减少数据量。避免数据倾斜,通常通过调整参数和Key打散来实现。避免全表扫描,通过在ON语句中添加分区等条件来优化。减少job数,通过合并具有相同ON条件的JOIN操作到一个任务中。

       优化HQL语句时,应尽量减少使用COUNT DISTINCT,因为它可能需要一个Reduce Task处理大量数据,导致Job难以完成。使用WITH子句可以提取子查询并将其结果用作临时表,减少重复计算,提高效率。在处理大表和小表的JOIN时,遵循将条目少的表放在Join操作符左侧的原则,可以减少OOM错误的几率。数据倾斜发生在shuffle过程中,常见触发此现象的算子包括distinct、groupByKey等。

       优化HIVE SQL的策略还包括通过参数调整来优化性能,但具体设置不在本文详细描述。核心优化思想旨在通过减少数据量、避免数据倾斜、避免全表扫描以及合理安排job和JOIN操作,实现SQL执行效率的提升。这些优化策略对于HIVE的性能优化至关重要,确保查询任务能够高效执行。

Hive优化的原则参考

        需要满足以下条件:

        hive.mapred.mode=true,严格模式不允许执行以下查询:

        分区表上没有指定了分区

        没有limit限制的order by语句

        笛卡尔积:JOIN时没有ON语句

        两个聚集函数不能有不同的DISTINCT列,以下表达式是错误的:

        SELECT语句中只能有GROUP BY的列或者聚集函数。

        第一个MRJob 中,

        Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key

        有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到

        Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。

        FROM test

        INSERT OVERWRITE TABLE count1

        SELECT count(DISTINCT test.dqcode)

        GROUP BY test.zipcode

        INSERT OVERWRITE TABLE count2

        SELECT count(DISTINCT test.dqcode)

        GROUP BY test.sfcode;

        ORDER BY colName ASC/DESC

        hive.mapred.mode=strict时需要跟limit子句

        hive.mapred.mode=nonstrict时使用单个reduce完成排序

        SORT BY colName ASC/DESC :每个reduce内排序

        DISTRIBUTE BY(子查询情况下使用 ):控制特定行应该到哪个reducer,并不保证reduce内数据的顺序

        CLUSTER BY :当SORT BY 、DISTRIBUTE BY使用相同的列时。

        增加map数目:

        当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。

        假设有这样一个任务:

          select data_desc, count(1), count(distinct id),sum(case when …),sum(case when ...),sum(…) from a group by data_desc

        如果表a只有一个文件,大小为M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。

          set mapred.reduce.tasks=;

          create table a_1 as select * from a distribute by rand();

        这样会将a表的记录,随机的分散到包含个文件的a_1表中,再用a_1代替上面sql中的a表,则会用个map任务去完成。每个map任务处理大于M(几百万记录)的数据,效率肯定会好很多。

        reduce数目设置:

         参数1:hive.exec.reducers.bytes.per.reducer=1G:每个reduce任务处理的数据量

         参数2:hive.exec.reducers.max=(0. TaskTracker数):每个任务最大的reduce数目

         reducer数=min(参数2,总输入数据量/参数1)

         set mapred.reduce.tasks:每个任务默认的reduce数目。典型为0. reduce槽数,hive将其设置为-1,自动确定reduce数目。

        .使用索引:

        hive.optimize.index.filter:自动使用索引

        hive.optimize.index.groupby:使用聚合索引优化GROUP BY操作

通过深挖Clickhouse源码,我精通了数据去重!

       数据去重的Clickhouse探索

       在大数据面试中,数据去重是一个常考问题。虽然很多博主已经分享过相关知识,但本文将带您深入理解Hive引擎和Clickhouse在去重上的差异,尤其是后者如何通过MergeTree和高效的数据结构优化去重性能。

       Hive去重

       Hive中,distinct可能导致数据倾斜,而group by则通过分布式处理提高效率。面试时,理解MapReduce的数据分区分组是关键。然而,对于大规模数据,Hive的处理速度往往无法满足需求。

       Clickhouse的登场

       面对这个问题,Clickhouse凭借其列存储和MergeTree引擎崭露头角。MergeTree的高效体现在它的数据分区和稀疏索引,以及动态生成和合并分区的能力。

       Clickhouse:Yandex开源的实时分析数据库,每秒处理亿级数据

       MergeTree存储结构:基于列存储,通过合并树实现高效去重

       数据分区和稀疏索引

       Clickhouse的分区策略和数据组织使得去重更为快速。稀疏索引通过标记大量数据区间,极大地减少了查询范围,提高性能。

       优化后的去重速度

       测试显示,Clickhouse在去重任务上表现出惊人速度,特别是通过Bitmap机制,去重性能进一步提升。

       源码解析与原则

       深入了解Clickhouse的底层原理,如Bitmap机制,对于优化去重至关重要,这体现了对业务实现性能影响的深度理解。

       总结与启示

       对于数据去重,无论面试还是日常工作中,深入探究和实践是提升的关键。不断积累和学习,即使是初入职场者也能在大数据领域找到自己的位置。

小技巧一:把roaring bitmap引入hive/spark,再也不怕count(distinct)了

       小技巧一:引入Roaring Bitmap到Hive/Spark,解决count(distinct)问题

       在SQL中,`count(distinct xxx)`常用于计算去重数量。当`xxx`为byte, shortint, int等数值类型时,可以将其转化为bitmap位运算,加速运算。对于非数值类型,可以考虑将其转换为一个唯一的数字,构建广义字典。Roaring Bitmap的基本思想是使用一个位图来唯一标记某个正整数,用于记录无重复的整数数组。

       例如,数组[2,3,4,5]可以通过一个字节记录。通过依次设置数字n在第n+1个位置的位,可以表示数组。对于数字范围0到n,需要`n/ +1`字节的存储空间。与数组存储相比,Roaring Bitmap的存储空间通常更小,约为数组的1/。

       Roaring Bitmap适用于无法直接存储的其他类型数字,通过转换为唯一数字进行存储。在处理如`[0,]`的场景中,使用Roaring Bitmap需要字节的空间,而数组存储只需要8字节,因此不划算。Roaring Bitmap在底层采用数组存储,以适应数字分散的场景。

       当处理如`[0,]`和`[,0]`的场景时,Roaring Bitmap可能无法区分数字顺序或正确识别重复值。在大数据领域,如活跃人数等去重指标的计算中,Roaring Bitmap可以加速计算过程,尤其是在离线执行引擎Hive/Spark中引入Roaring Bitmap来实现精准去重。

       考虑到Hive本身不支持Roaring Bitmap数据类型,可以将其序列化为`binary`类型使用。在函数体系方面,需要实现一系列的UDF和UDAF函数,如`bitmap_count`、`bitmap_and`、`bitmap_not`、`bitmap_union`、`bitmap_contains`、`range_bitmap`、`bitmap_to_array`、`array_to_bitmap`等,以支持bitmap的集合计数、交集、差集、并集和查询操作。

       在留存分析场景中,可以利用Roaring Bitmap构建活跃位图来加速计算,如连续N天登录问题。通过将用户活跃日期构建为位图,可以快速判断用户是否连续活跃。在用户画像和用户圈选场景中,Roaring Bitmap可以用于构建用户活跃画像,提高数据处理效率。在电商场景中,通过构建轻度汇总表并使用Roaring Bitmap存储去重人数,可以有效避免重复计算,提高数据聚合的准确性。

       对于大数值范围(如bigint),Roaring Bitmap也支持。考虑到实际应用中数值范围超过`2**`的情况较少,是否需要支持bigint取决于具体需求。在数据索引优化方面,可以考虑重新编码,使得连续分布,进一步提高查询性能。