赞
踩
最近工作上遇到数据量特别大的任务,一天20T左右,和一些维表关联时,出现了数据倾斜的情况。这边记录一下解决的方法。
由于工作数据敏感问题,这边用其他场景来模拟(纯属虚构的场景和数据,侵删)。
假设表1:happy_info 是全球192个国家的开心次数信息,有如下字段:(开心一次,就会记录一次,一个id会上报多条记录)
- 人员id 国籍 是否开心 开心时刻
- (id) (country) (is_happy) (happy_moment)
- 00001 中国 1 2020-01-20
- 00001 中国 1 2020-01-21
- 00001 中国 1 2020-01-23
- 00002 中国 1 2020-01-21
- 00003 印度 1 2020-01-20
- 00004 美国 1 2020-01-20
- 00005 英国 1 2020-01-22
- 00006 中国 1 2020-01-20
- 00007 美国 1 2020-01-20
- 00008 中国 1 2020-01-23
- ... ... ... ...
- (剩余70亿条信息)
表2:country_info 是筛选出的50个国家对应英文名的维表:
- 中文名 英文名
- (cn_name) (en_name)
- 中国 China
- 英国 England
- 美国 America
- 印度 India
- ... ...
- (共50个各国家的英文名信息)
假设现有全球192个国家70亿人的开心次数信息,求表2中50个国家近半年的平均开心次数,要求有国籍的英文名信息。
- select
- country
- ,en_name
- ,sum(happy_times) as all_happy_times
- ,count(id) as all_user
- ,sum(happy_times) / count(id) as avg_happy_times
- from
- (
- select /*+ MAPJOIN(b)*/ id, country, en_name, count(id) as happy_times
- from
- (
- select
- country
- ,id
- from happy_info
- ) a
- join
- (
- select cn_name, en_name
- from country_info
- ) b
- on a.country = b.cn_name
- group by id, country, en_name
- ) a
- group by
- country
- ,en_name
当时的思路是先把表1中的192个国家限定在表2中的50个里面。再去进去group by统计。由于中国人天天开心,而且此时很多,发现数据倾斜的情况。
- select
- country
- ,en_name
- ,all_happy_times
- ,all_users
- ,all_happy_times / all_users as avg_happy_times
- from
- (
- select
- country
- ,sum(total_user) as all_users
- ,sum(tot_happy_times) as all_happy_times
- from
- (
- select
- country
- ,rnd --对每个国家以及随机数进行聚合
- ,count(1) as total_user
- ,sum(cnt) as tot_happy_times
- from
- (
- select
- country
- ,round(rand()*1000) as rnd --利用随机数分成1000份
- ,id
- ,count(1) as cnt
- from happy_info
- group by
- country
- ,id
- ) a
- group by country, rnd
- ) a
- group by country
- ) a
- join
- (
- select cn_name, en_name
- from country_info
- ) b
- on a.country = b.cn_name
-
思路:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。