Partition VS Group
前言
在了解数据倾斜之前,我们先了解一下什么是partition
。
partition
partition
是一种开窗函数。用法为:
1 | SELECT column1 OVER(PARTITION BY column2 ORDER BY column3 DESC) |
当然,如果使用sqlite
,你会发现很多情况下都会加上一个中括号:
1 | SELECT [column1] OVER(PARTITION BY [column2] ORDER BY [column3] DESC) |
这都是小事。
group
group
是一种聚合函数。用法为:
1 | SELECT column1 |
同样的,你也可以加上中括号。
对比
使用partition
和group
时,虽然说都有分组的功能,但是原理上稍微有些不同。
在使用group
的时候,最终结果并不保存所有数据,而是只保存分组后的数据,每个组中需要SELECT
的属性仅保留唯一的属性值。
比如我现在有一个表,有四个属性,分别是id
,name
、money
和address
。
id | name | money | address |
---|---|---|---|
1 | 张三 | 18 | 北京分公司 |
2 | 李四 | 19 | 上海分公司 |
3 | 王五 | 20 | 北京分公司 |
4 | 马六 | 21 | 北京分公司 |
5 | 赵七 | 22 | 武汉分公司 |
6 | 钱八 | 23 | 杭州分公司 |
7 | 孙九 | 24 | 杭州分公司 |
如果我使用group
:
1 | SELECT id, name, money, address |
那么最终结果为:
id | name | money | address |
---|---|---|---|
1 | 张三 | 18 | 北京分公司 |
2 | 李四 | 19 | 上海分公司 |
5 | 赵七 | 22 | 武汉分公司 |
6 | 钱八 | 23 | 杭州分公司 |
在这个基础上使用聚合函数的话,也只能保有这些信息。部分分组的名称被吞掉了。
如果说这是一个绩效表,需要查看谁(帕鲁)在本年度创收占所在公司占比情况,使用GROUP BY
需要保证每个分组并不会被吞掉。这也意味着需要考虑重名、金额相等、分公司人数较多等情况。
P.S.:并不是所有的公司都是这么变态的。
而如果使用partition
:
1 | SELECT id, name, money, address, ROUND(money / SUM(money) OVER(PARTITION BY address ORDER BY money), 2) AS ratio |
他的结果是:
id | name | money | address | ratio |
---|---|---|---|---|
1 | 张三 | 18 | 北京分公司 | 0.31 |
2 | 李四 | 19 | 上海分公司 | 1.00 |
3 | 王五 | 20 | 北京分公司 | 0.34 |
4 | 马六 | 21 | 北京分公司 | 0.35 |
5 | 赵七 | 22 | 武汉分公司 | 1.00 |
6 | 钱八 | 23 | 杭州分公司 | 0.49 |
7 | 孙九 | 24 | 杭州分公司 | 0.51 |
清晰地将所有信息全部罗列出来了。
如果需要排序,或者在排序的基础上获取前几,那就可以使用嵌套查询:
1 | SELECT t.name, t.address, rank() OVER(PARTITION BY t.[address] ORDER BY t.ratio) FROM ( |
最终结果就是:
name | address | ratio | rank |
---|---|---|---|
马六 | 北京分公司 | 0.35 | 1 |
王五 | 北京分公司 | 0.34 | 2 |
张三 | 北京分公司 | 0.31 | 3 |
李四 | 上海分公司 | 1.00 | 1 |
赵七 | 武汉分公司 | 1.00 | 1 |
孙九 | 杭州分公司 | 0.51 | 1 |
钱八 | 杭州分公司 | 0.49 | 2 |
看来,使用partition
可以更直观地获取数据,并且最大程度保留每个分组中每个属性的信息,从而实现更丰富的需求。