点击上方 "大数据肌肉猿"关注, 星标一起成长
点击下方链接,进入高质量学习交流群
分享一位学习群同学的转型经历,他是二本土木类工程管理专业,17年毕业,毕业后在长沙工地从事了近5年,上半年开始学习大数据,前几个月拿了长沙和深圳多个大数据offer,后面选择了深圳一家甲方公司,目前已通过试用期,分享一些转型感受。
我是普通二本的本科生,学的是工程管理专业。毕业时,工作半年左右开始仔细思考,到底想要以一个什么样的职业,融入我国发展大潮。彼时互联网风起云涌,此起彼伏互联网暴富的消息被各路媒体争相报导。
恰巧18年末在星球遇到了峰哥分享他的个人经历,于是加了他微信进了学习群,峰哥在群里分享了很多资料和经验,那时整个群基本都不是做大数据,但这几年很多人陆陆续续都转型成功了。
我最开始自学了一段时间,后来因为工作原因就停滞了,现在想想挺后悔的,要是早点转,目前薪资待遇可以更高。
今年年初因为疫情在家没法工作,在考虑了一段时间之后,就决心转大数据了。开始正式找峰哥帮忙规划学习路线和指导面试,学了几个月,年中开始面试。
最后拿到长沙一家大型制造业还有一家互联网公司,薪资在15-17W左右,拿了深圳两家外包18K,还有一家金融科技甲方19K的offer。
大数据是互联网发展的一定时期的产物。人口红利已经慢慢消失,逐渐从增量市场转向存量市场。存量市场没有增量市场那样好做,如何在现用的存量市场中更好的发展自己的企业呢?就精准营销了嘛。这就需要数据开发、数据分析、数据挖掘,产生用户画像、数据报表来为决策层决策、精准营销提供量化的依据。这正符合了“技术是演进出来的,不是想出来的”。
另外一个主要原因是工地干到头了,加上疫情原因经常停工,工作环境也比较压抑,一年干到头存不了几万块钱。
虽然今年互联网行情没有往年好,但我对比了一圈,发现还是远远比其他我能选择的行业好。
我认为先入行把技术学到手最重要,技术是程序员的核心竞争力,技术好了也就有了议价权。
在进入一个新行业的时候,很需要有经验的过来人给到一些指导性的建议和学习方法,峰哥对我来说也就是这个过来人。
年初和峰哥详细聊了当时的个人情况,在峰哥帮我规划了学习路线和学习计划,然后就开始学了。
学的过程中,由于是接触新东西。比较吃力,心态偶尔也爆炸一下。这个时候找峰哥聊聊天。找个方式发泄一下,然后回来继续学就好了。
至于学习路线基本都是峰哥公众号分享的这些,非常赞同峰哥说的一句话:前期学习少即是多。所以前期学习并没有想象中的复杂,反而只需要学关键的一些知识点,有种四两拨千斤的感觉。
开始面试,有面试通知的话,针对JD突击学一下,面试中问面试官自己哪里不足,面试后总结。总结后继续面。面试后总结。总结后继续面。循环往复,期间和峰哥保持联系,峰哥会给到很 nice 的建议的。
就这样几个月在长沙面了几家就面试成功了,拿了两个offer,我也就去了。
公司挺大,一周五天班,朝九晚六不打卡。这就给到了我足够的时间查漏补缺,我也趁空余都在公司学习。一个月过去了,与同事交流,都感觉公司的项目没有想象中的复杂。慢慢开始意识到成长的速度似乎与一线脱节了。
干了一个多月我离职了,准备去一线工作。
和一线的同学和前辈沟通了之后,当然也有峰哥哈。我8月份来了深圳。
然后开始投简历,面试总结调整,循环。找了将近1个月的工作,期间多次和峰哥交流面试相关的问题。刚开始拿了2个外包offer,后来又拿了金融甲方,然后就选择加入了,最近已经成功转正,感谢峰哥试用期的指导。
接下去的计划是继续精进自己的技术,在深圳多呆几年,后面回长沙选择也可以更多。
怎么查看表结构,表创建语句?怎么查看表有哪些分区?怎么查看分区对应 hdfs 路径?
--查看表结构信息
desc 表名;
--显示如何创建一个表
show create table 表名;
--怎么查看表有哪些分区
hive> show partitions table_name;
mysql>SELECT
partition_name part,
partition_expression expr,
partition_description descr,
FROM_DAYS(partition_description) lessthan_sendtime,
table_rows
FROM
INFORMATION_SCHEMA.partitions
WHERE
TABLE_SCHEMA = SCHEMA()
AND TABLE_NAME='el_user_category_litera'; ---这里是表名
--hive怎么查看分区对应 hdfs 路径
desc formatted 表名 partition (day = ‘2015-01-25′);
怎么计算某个分区的数据量大小?怎么计算某个分区的文件总数?
列出该表的详细文件列表
$ hadoop fs -ls /user/hive/warehouse/table_name
--#查看分区表的容量
$ hadoop fs -ls /user/hive/warehouse/table_name/yyyymm=201601 | awk -F ' ' '{print $5}'|awk '{a+=$1}END {print a/(1024*1024*1024)}'
这样可以省去自己相加,下面命令是列出该表的详细文件列表
$ hadoop fs -ls /user/hive/warehouse/table_name/yyyymm=201601
统计文件详细数目
$ hadoop fs -ls /user/hive/warehouse/table_name/yyyymm=201601**|wc -l**
有几种表连接(join)?
INNER JOIN 内连接
LEFT OUTER JOIN 左外连接
RIGHT OUTER JOIN 右外连接
FULL OUTER JOIN 全外连接
LEFT SEMI JOIN 左半开连接
JOIN笛卡尔积
Hive查询快速查找表大小(即行数)
ANALYZE TABLE tablename [PARTITION(partcol1[=val1], partcol2[=val2], ...)] COMPUTE STATISTICS [noscan];
如果表被分区
- hive> ANALYZE TABLE ops_bc_log PARTITION(day) COMPUTE STATISTICS noscan;
-
- 输出是
-
- 分区logdata.ops_bc_log {day = 20140523} stats:[numFiles = 37,numRows = 26095186,totalSize = 654249957,rawDataSize = 58080809507]
-
- 分区logdata.ops_bc_log {day = 20140521} stats:[numFiles = 30,numRows = 21363807,totalSize = 564014889,rawDataSize = 47556570705]
-
- 分区logdata.ops_bc_log {day = 20140524} stats:[numFiles = 35,numRows = 25210367,totalSize = 631424507,rawDataSize = 56083164109]
-
- 分区logdata.ops_bc_log {day = 20140522} stats:[numFiles = 37,numRows = 26295075,totalSize = 657113440,rawDataSize = 58496087068]
一 hive sql ,怎么计算这个 sql 会产生多少个 map 数?
概念
一般情况下,在输入源是文件的时候,一个task的map数量由splitSize来决定的,那么splitSize是由以下几个来决定的
goalSize = totalSize / mapred.map.tasks
inSize = max {mapred.min.split.size, minSplitSize}
splitSize = max (minSize, min(goalSize, dfs.block.size))
一个task的reduce数量,由partition决定。
在输入源是数据库的情况下,比如mysql,对于map的数量需要用户自己指定,比如
jobconf.set(“mapred.map.tasks.nums”,20);
如果数据源是HBase的话,map的数量就是该表对应的region数量。
1 map的数量
map的数量通常是由hadoop集群的DFS块大小确定的,也就是输入文件的总块数,正常的map数量的并行规模大致是每一个Node是10~100个,对于CPU消耗较小的作业可以设置Map数量为300个左右,但是由于hadoop的每一个任务在初始化时需要一定的时间,因此比较合理的情况是每个map执行的时间至少超过1分钟。具体的数据分片是这样的,InputFormat在默认情况下会根据hadoop集群的DFS块大小进行分片,每一个分片会由一个map任务来进行处理,当然用户还是可以通过参数mapred.min.split.size参数在作业提交客户端进行自定义设置。还有一个重要参数就是mapred.map.tasks,这个参数设置的map数量仅仅是一个提示,只有当InputFormat 决定了map任务的个数比mapred.map.tasks值小时才起作用。同样,Map任务的个数也能通过使用JobConf 的conf.setNumMapTasks(int num)方法来手动地设置。这个方法能够用来增加map任务的个数,但是不能设定任务的个数小于Hadoop系统通过分割输入数据得到的值。
2 reduece的数量
reduce在运行时往往需要从相关map端复制数据到reduce节点来处理,因此相比于map任务。reduce节点资源是相对比较缺少的,同时相对运行较慢,正确的reduce任务的个数应该是0.95或者1.75 *(节点数 ×mapred.tasktracker.tasks.maximum参数值)。如果任务数是节点个数的0.95倍,那么所有的reduce任务能够在 map任务的输出传输结束后同时开始运行。如果任务数是节点个数的1.75倍,那么高速的节点会在完成他们第一批reduce任务计算之后开始计算第二批 reduce任务,这样的情况更有利于负载均衡。
Hadoop在运行一个mapreduce job之前,需要估算这个job的maptask数和reducetask数。首先分析一下job的maptask数,当一个job提交时,jobclient首先分析job被拆分的split数量,然后吧job.split文件放置在HDFS中,一个job的MapTask数量就等于split的个数。
job.split中包含split的个数由FileInputFormat.getSplits计算出,方法的逻辑如下:
\1. 读取参数mapred.map.tasks,这个参数默认设置为0,生产系统中很少修改。
\2. 计算input文件的总字节数,总字节数/(mapred.map.tasks==0 ? 1: mapred.map.tasks )=goalsize
\3. 每个split的最小值minSize由mapred.min.split.size参数设置,这个参数默认设置为0,生产系统中很少修改。
\4. 调用computeSplitSize方法,计算出splitsize= Math.max(minSize, Math.min(goalSize, blockSize)),通常这个值=blockSize,输入的文件较小,文件字节数之和小于blocksize时,splitsize=输入文件字节数之和。
\5. 对于input的每个文件,计算split的个数。
a) 文件大小/splitsize>1.1,创建一个split,这个split的字节数=splitsize,文件剩余字节数=文件大小-splitsize
b) 文件剩余字节数/splitsize<1.1,剩余的部分作为一个split
举例说明:
\1. input只有一个文件,大小为100M,splitsize=blocksize,则split数为2,第一个split为64M,第二个为36M
\2. input只有一个文件,大小为65M,splitsize=blocksize,则split数为1,split大小为65M
\3. input只有一个文件,大小为129M,splitsize=blocksize,则split数为2,第一个split为64M,第二个为65M(最后一个split的大小可能超过splitsize)
\4. input只有一个文件,大小为20M ,splitsize=blocksize,则split数为1,split大小为20M
\5. input有两个文件,大小为100M和20M,splitsize=blocksize,则split数为3,第一个文件分为两个split,第一个split为64M,第二个为36M,第二个文件为一个split,大小为20M
\6. input有两个文件,大小为25M和20M,splitsize=blocksize,则split数为2,第一个文件为一个split,大小为25M,第二个文件为一个split,大小为20M
假设一个job的input大小固定为100M,当只包含一个文件时,split个数为2,maptask数为2,但当包含10个10M的文件时,maptask数为10。
总结:
通过map和reducetask数量的分析可以看出,hadoop/hive估算的map和reduce task数可能和实际情况相差甚远。假定某个job的input数据量庞大,reduce task数量也会随之变大,而通过join和group by,实际output的数据可能不多,但reduce会输出大量的小文件,这个job的下游任务将会启动同样多的map来处理前面reduce产生的大量文件。在生产环境中每个user group有一个map task数的限额,一个job启动大量的map task很显然会造成其他job等待释放资源。
Hive对于上面描述的情况有一种补救措施,参数hive.merge.smallfiles.avgsize控制hive对output小文件的合并,当hiveoutput的文件的平均大小小于hive.merge.smallfiles.avgsize-默认为16MB左右,hive启动一个附加的mapreducejob合并小文件,合并后文件大小不超过hive.merge.size.per.task-默认为256MB。
尽管Hive可以启动小文件合并的过程,但会消耗掉额外的计算资源,控制单个reduce task的输出大小>64MB才是最好的解决办法。
- hive> set dfs.block.size;
- dfs.block.size=268435456
- hive> set mapred.map.tasks;
- mapred.map.tasks=2
- //文件块大小为256MB,map.tasks为2
查看文件大小和文件数:
- [dwapp@dw-yuntigw-63 hadoop]$ hadoop dfs -ls /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25;
- 结果:
- Found 18 items
- -rw-r----- 3 alidwicbu cug-alibaba-dw-icbu 290700555 2012-11-26 19:00 /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25/attempt_201211151327_1675393_m_000000_0
- -rw-r----- 3 alidwicbu cug-alibaba-dw-icbu 290695945 2012-11-26 18:59 /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25/attempt_201211151327_1675393_m_000001_0
- -rw-r----- 3 alidwicbu cug-alibaba-dw-icbu 290182606 2012-11-26 19:00 /group/alibaba-dw-icbu/hive/bdl_en12_pageview_fatdt0_d/hp_stat_date=2012-11-25/attempt_201211151327_1675393_m_000002_0
- ......
计算:
goalSize = 4539.059804 (文件总大小)/ mapred.map.tasks(2) = 2269.529902MB
因此splitsize取值为256MB,所以一共分配18个map。
若修改map.tasks参数为32
set mapred.map.tasks = 32;
goalSize = 4539.059804 / mapred.map.tasks(32) = 141.8456189
因此splitsize取值为141.8MB,所以一共分配36个map。
sort by、distribute by、cluster by 和 order by 区别?
order by
对输入做全局排序,因此只有一个Reducer。然而只有一个Reducer,会导致当输入规模较大时,消耗较长的计算时间。
sort by | sort by的数据只能保证在同一个reduce中的数据可以按指定字段排序。使用sort by你可以指定执行的reduce个数(通过set mapred.reduce.tasks=n来指定),对输出的数据再执行归并排序,即可得到全部结果。 |
distribute by | distribute by是控制在map端如何拆分数据给reduce端的。sort by为每个reduce产生一个排序文件。在有些情况下,你需要控制某个特定行应该到哪个reducer,这通常是为了进行后续的聚集操作。distribute by刚好可以做这件事。因此,distribute by经常和sort by配合使用。hive要求distribute by要写在sort by之前。 |
cluster by | cluster by==distribute by+sort by。但是排序只能是倒叙排序,不能指定排序规则为ASC或者DESC。 |
注:Distribute by和sort by的使用场景
**1.**Map输出的文件大小不均。
**2.**Reduce输出文件大小不均。
**3.**小文件过多。
**4.**文件超大。
hive (hive)> select * from temperature distribute by year sort by year asc,tempra desc;
a 表和 b 表内连接,a表为小表,只有2000 行记录,可以进行怎么样的优化?select a.* from a join b on a.key=b.key;
可以让hive自动识别,把join变成合适的Map Join如下所示
注:当设置为true的时候,hive会自动获取两张表的数据,判定哪个是小表,然后放在内存中
- set hive.auto.convert.join=true;
- select a.* from a join b on a.key=b.key;
a表 left join b 表,b表为小表,可以进行怎么样的优化?select a.* from a left join b on a.key=b.key;
两大表连接,发生了数据倾斜,有几个 reduce 无法完成,怎么查找发生数据倾斜的原因?怎么优化?
每天图书馆的人流量信息被记录在这三列信息中:序号(id)、日期(date)、人流量(people)。请编写一个查询语句,找出高峰期时段,要求连续三天及以上,并且每天人流量均不少于100。
PS:每天只要一行记录,日期随 id 的增加而增加。
表table_1
id
date
people
1 | 2017-01-01 | 10 |
2 | 2017-01-02 | 109 |
3 | 2017-01-03 | 150 |
4 | 2017-01-04 | 99 |
5 | 2017-01-05 | 145 |
6 | 2017-01-06 | 1455 |
7 | 2017-01-07 | 199 |
8 | 2017-01-08 | 188 |
输出为
id
date
people
5 | 2017-01-05 | 145 |
6 | 2017-01-06 | 1455 |
7 | 2017-01-07 | 199 |
8 | 2017-01-08 | 188 |
答案:
如果只是找出全部人流量不少于100的记录不难,难点在于如何查找连续的三天,一个想法是,查 3 张表,让三个结果 id 连续
- SELECT a.*
- FROM stadium as a,stadium as b,stadium as c
- where (a.id = b.id-1 and b.id+1 = c.id)
- and (a.people>=100 and b.people>=100 and c.people>=100);
但是这样输出会有问题,比如 5,6,7,8 号人流量不少于100,但是只输出了 5,6号,根本原因在于,我们将 a 的 id 设为三个连续值中最小值,所以只返回了每 3 个连续值中最小的一个,同理可想到,我们再将 a 的 id 设为三个连续值中中间值和最大值,可以得到全部的连续 3 个值
- SELECT a.*
- FROM stadium as a,stadium as b,stadium as c
- where ((a.id = b.id-1 and b.id+1 = c.id) or
- (a.id-1 = b.id and a.id+1 = c.id) or
- (a.id-1 = c.id and c.id-1 = b.id))
- and (a.people>=100 and b.people>=100 and c.people>=100);
但是这样还有个问题,比如 5,6,7,8,6 既是 5,6,7 的中间值也是 6,7,8 的最小值,所以还要去重,也许 id 不按序排列,再排序 id,最终得到答案
- SELECT distinct a.*
- FROM stadium as a,stadium as b,stadium as c
- where ((a.id = b.id-1 and b.id+1 = c.id) or
- (a.id-1 = b.id and a.id+1 = c.id) or
- (a.id-1 = c.id and c.id-1 = b.id))
- and (a.people>=100 and b.people>=100 and c.people>=100)
- order by a.id;
链接:https://leetcode-cn.com/problems/human-traffic-of-stadium/solution/ti-yu-guan-de-ren-liu-liang-by-little_bird/
来源:力扣(LeetCode)
实际生产环境中,一天的数据可能有50G
设置:
可以让hive自动识别,把join变成合适的Map Join如下所示
注:当设置为true的时候,hive会自动获取两张表的数据,判定哪个是小表,然后放在内存中
- set hive.auto.convert.join=true;
- select /*+ MAPJOIN(time_dim) */ count(*) from store_sales join time_dim on (ss_sold_time_sk = t_time_sk)
大表对大表,既然是两个表进行join,肯定有相同的字段吧。
- set hive.auto.convert.sortmerge.join=true
- set hive.optimize.bucketmapjoin=true;
- set hive.optimize.bucketmapjoin.sortedmerge=true;
Map Join 效率比 Common Join 效率好,但总会有“小表”条件不满足的时候。这就需要 bucket map join 了。
Bucket map join 需要待连接的两个表在连接字段上进行分桶(每个分桶对应hdfs上的一个文件),而且小表的桶数需要时大表桶数的倍数。
建立分桶表的例子:
- CREATE TABLE my_user
- (uid INT,
- name STRING)
- CLUSTERED BY (uid) into 32 buckets
- STORED AS TEXTFILE;
这样,my_user 表就对应 32 个桶,数据根据 uid 的 hash value 与32 取余,然后被分发导不同的桶中。
如果两个表在连接字段上分桶,则可以执行 bucket map join 了,具体的:
设置属性 hive.optimize.bucketmapjoin= true 控制 hive 执行 bucket map join;
对小表的每个分桶文件建立一个 hashtable,并分发到所有做连接的 map端;
map 端接受了N(N为小表分桶的个数) 个小表的 hashtable,做连接操作的时候,只需要将小表的一个 hashtable 放入内存即可,然后将大表的对应的 split 拿出来进行连接,所以其内存限制为小表中最大的那个hashtable 的大小。
对于 bucket map join 中的两个表,如果每个桶内分区字段也是有序的,则还可以进行 sort merge bucket map join。
建表语句为:
- CREATE TABLE my_user
- ( uid INT,
- name STRING)
- CLUSTERED BY (uid) SORTED BY (uid) into 32 buckets
- STORED AS TEXTFILE;
这样一来当两边 bucket 要做局部 join 的时候,只需要用类似 merge sort 算法中的 merge 操作一样把两个 bucket 顺序遍历一遍即可完成,小表的数据可以每次只读取一部分,然后还是用大表一行一行的去匹配,这样的join 没有限制内存的大小. 并且也可以执行全外连接。
进行sort merge bucket map join时,需要设置的属性为:
- set hive.optimize.bucketmapjoin= true;
- set hive.optimize.bucketmapjoin.sortedmerge = true;
- set hive.input.format = org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
JOIN类型
优点
缺点
COMMON JOIN | 可以完成各种 JOIN 操作,不受表大小和表格式的限制 | 无法只在 map 端完成 JOIN 操作,耗时长,占用更多地网络资源 |
MAP JOIN | 可以在 map 端完成 JOIN 操作,执行时间短 | 待连接的两个表必须有一个“小表”,“小表”必须加载内存中 |
BUCKET MAP JOIN | 可以完成 MAP JOIN,不受“小表”限制 | 表必须分桶,做连接时小表分桶对应 hashtable 需要加载到内存 |
SORT MERGE BUCKET MAP JOIN | 执行时间短,可以做全连接,几乎不受内存限制 | 表必须分桶,而且桶内数据有序 |
数据倾斜可能会发生在group过程和join过程。
• 数据倾斜症状:
任务长时间维持在99%(或100%);
查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成;
本地读写数据量很大。
• 原因:
key分布不均匀;
业务数据本身特点。
• 导致数据倾斜的操作:
GROUP BY, COUNT DISTINCT(),join
————————————————
版权声明:本文为CSDN博主「login_sonata」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/login_sonata/article/details/75000766
多表关联时,将小表(关联键重复记录少的表)依次放到前面,这样可以触发 reduce 端更少的操作次数,减少运行时间。
同时可以使用 Map Join 让小的维度表缓存到内存。在map端完成join过程,从而省略掉redcue端的工作。但是使用这个功能,需要开启map-side join的设置属性:set hive.auto.convert.join=true(默认是false)
同时还可以设置使用这个优化的小表的大小:set hive.mapjoin.smalltable.filesize=25000000(默认值25M)
————————————————
原文链接:https://blog.csdn.net/qq_26442553/article/details/80866723
大表与大表关联,如果其中一张表的多是空值或者 0 比较多,容易 shuffle 给一个reduce,造成运行慢。
这种情况可以对异常值赋一个随机值来分散 key,均匀分配给多个 reduce 去执行,比如:
- select *
- from log a
- left outer join users b
- on case when a.user_id is null then concat('hive',rand() ) else a.user_id end = b.user_id;
-
- -- 将A表垃圾数据(为null)赋一个随机的负数,然后将这些数据shuffle到不同reduce处理。
当 key 值都是有效值时,解决办法为:
设置以下参数:
- # 每个节点的 reduce 默认是处理 1G 大小的数据
- set hive.exec.reducers.bytes.per.reducer = 1000000000
- # 如果 join 操作也产生了数据倾斜,可以设定
- set hive.optimize.skewjoin = true;
- set hive.skewjoin.key = skew_key_threshold (default = 100000)
Hive 在运行的时候无法判断哪个 key 会产生倾斜,所以使用 hive.skewjoin.key 参数控制倾斜的阈值,如果超过这个值,新的值会发送给那些还没有达到的 reduce,一般可以设置成待处理的总记录数/reduce 个数的 2-4 倍。
解决方式1:
hive.map.aggr=true (默认true) 这个配置项代表是否在map端进行聚合,相当于Combiner
hive.groupby.skewindata=true(默认false)
似乎是解决数据倾斜的万能钥匙,查询计划会有两个 MR Job,第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
1.reduce个数太少
reduce数太少set mapred.reduce.tasks=800;
默认是先设置hive.exec.reducers.bytes.per.reducer这个参数,设置了后hive会自动计算reduce的个数,因此两个参数一般不同时使用
2.当HiveQL中包含count(distinct)时
如果数据量非常大,执行如select a,count(distinct b) from t group by a;类型的SQL时,会出现数据倾斜的问题。
解决方法:使用sum...group by代替。如select a,sum(1) from (select a, b from t group by a,b) group by a;
--end--
- 扫描下方二维码
-
- 添加好友,备注【交流】
- 可围观朋友圈,也可私信交流