Hive之COUNT DISTINCT优化

COUNT(DISTINCT xxx) 在hive中很容易造成数据倾斜。针对这一情况,网上已有很多优化方法,这里不再赘述。

但有时,“数据倾斜”又几乎是必然的。我们来举个例子:

假设表detail_sdk_session中记录了访问某网站M的客户端会话信息,即:如果用户A打开app客户端,则会产生一条会话信息记录在该表中,该表的粒度为“一次”会话,其中每次会话都记录了用户的唯一标示uuid,uuid是一个很长的字符串,假定其长度为64位。现在的需求是:每天统计当月的活用用户数——“月活跃用户数”(当月访问过app就为活跃用户)。我们以2016年1月为例进行说明,now表示当前日期。

最简单的方法

这个问题逻辑上很简单,SQL也很容易写出来,例如:

SELECT
  COUNT(DISTINCT uuid)
FROM detail_sdk_session t
WHERE t.date >= '2016-01-01' AND t.date <= now

上述SQL代码中,now表示当天的日期。很容易想到,越接近月末,上面的统计的数据量就会越大。更重要的是,在这种情况下,“数据倾斜”是必然的,因为只有一个reducer在进行COUNT(DISTINCT uuid)的计算,所有的数据都流向唯一的一个reducer,不倾斜才怪。

优化1

其实,在COUNT(DISTINCT xxx)的时候,我们可以采用“分治”的思想来解决。对于上面的例子,首先我们按照uuid的前n位进行GROUP BY,并做COUNT(DISTINCT )操作,然后再对所有的COUNT(DISTINCT)结果进行求和。

我们先把SQL写出来,然后再做分析。

-- 外层SELECT求和
SELECT
  SUM(mau_part) mau
FROM
(
  -- 内层SELECT分别进行COUNT(DISTINCT)计算
  SELECT
    substr(uuid, 1, 3) uuid_part,
    COUNT(DISTINCT substr(uuid, 4)) AS mau_part
  FROM detail_sdk_session
  WHERE partition_date >= '2016-01-01' AND partition_date <= now
  GROUP BY substr(uuid, 1, 3)
) t;

上述SQL中,内层SELECT根据uuid的前3位进行GROUP BY,并计算相应的活跃用户数COUNT(DISTINCT),外层SELECT求和,得到最终的月活跃用户数。

这种方法的好处在于,在不同的reducer各自进行COUNT(DISTINCT)计算,充分发挥hadoop的优势,然后进行求和。

注意,上面SQL中,n设为3,不应过大。

为什么n不应该太大呢?

我们假定uuid是由字母和数字组成的:大写字母、小写字母和数字,字符总数为26+26+10=62。

理论上,内层SELECT进行GROUP BY时,会有 62^n 个分组,外层SELECT就会进行 62^n 次求和。所以n不宜过大。

当然,如果数据量十分巨大,n必须充分大,才能保证内层SELECT中的COUNT(DISTINCT)能够计算出来,此时可以再嵌套一层SELECT,这里不再赘述。

优化2

其实,很多博客中都记录了使用GROUP BY 操作代替 COUNT(DISTINCT) 操作,但有时仅仅使用GROUP BY操作还不够,还需要加点小技巧。

还是先来看一下代码:

--  第三层SELECT
SELECT
  SUM(s.mau_part) mau
FROM
(
  -- 第二层SELECT
  SELECT
    tag,
    COUNT(*) mau_part
  FROM
  (
    -- 第一层SELECT
    SELECT
      uuid, 
      CAST(RAND() * 100 AS BIGINT) tag  -- 为去重后的uuid打上标记,标记为:0-100之间的整数。
    FROM detail_sdk_session
    WHERE partition_date >= '2016-01-01' 
      AND partition_date <= now
      AND uuid IS NOT NULL
    GROUP BY uuid   -- 通过GROUP BY,保证去重
   ) t
  GROUP BY tag
) s
;
  1. 第一层SELECT:对uuid进行去重,并为去重后的uuid打上整数标记
  2. 第二层SELECT:按照标记进行分组,统计每个分组下uuid的个数
  3. 第三层SELECT:对所有分组进行求和

上面这个方法最关键的是为每个uuid进行标记,这样就可以对其进行分组,分别计数,最后去和。如果数据量确实很大,也可以增加分组的个数。例如:CAST(RAND() * 1000 AS BIGINT) tag

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 1.简介 数据存储有哪些方式?电子表格,纸质文件,数据库。 那么究竟什么是关系型数据库? 目前对数据库的分类主要是...
    乔震阅读 1,699评论 0 2
  • Hive性能优化 1.概述继续《那些年使用Hive踩过的坑》一文中的剩余部分,本篇博客赘述了在工作中总结Hive的...
    Albert陈凯阅读 1,504评论 0 8
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,577评论 18 399
  • 【优化】COUNT(1)、COUNT(*)、COUNT(常量)、COUNT(主键)、COUNT(ROWID)、CO...
    小麦苗DB宝阅读 2,618评论 0 3
  • 幸福是由内而外散发的一种满足感,能够持久,没有坏处,幸福是万能药。 幸福和快乐有差异,幸福无法度量,快乐短暂,可度...
    happness321阅读 347评论 1 3