提高去重计数效率——代理键+bitmap去重

# 背景

现实场景中经常会遇到字符串字段去重计数的场景,常见方式如下:

- 最简单的是count(distinct),性能最差,不推荐

- group by 后count(1),充分利用分布式并行计算的优点,但是容易遇到数据倾斜,总体上是推荐

除了以上两种方式,还可以借助rbm进行去重计数,接下来介绍代理键+rbm的方法

# 方案介绍

rbm是bitset的优化,把long型变量分为高32位和低32位分别存放,高32位用作索引(具体原理可参考https://blog.csdn.net/u011624157/article/details/108432494)。

rbm是很好用,但是只能存放int、long等数字类型,要对字符串做去重的话需要把字符串映射成数值,方案有两种:

- 取hashcode,实现较简单,但数据量太大会有hash碰撞,仅适用于中小规模数据量

- 使用row_number函数生成数字类型代理键,实现略复杂,需要做一个中间表,但是去重精确,适用于大数据量场景

## 详细实现

接下来说代理键+rbm的详细代码

-  1、先做代理键

```sql

select

    log_id,

    id

from(

select

    log_id,

    row_sequence() as id --使用row_sequence函数生成代理键

from(

select

    log_id

from

(

    select log_id

    from base_log

) t1

group by log_id

) a) a

distribute by id

;

```

- 2、根据rbm udaf进行去重

# 附:代理键名词解释

## 代理键

在关系型数据库设计中,代理键(英语:surrogate key)是在当资料表中的候选键都不适合当主键时,例如资料太长,或是意义层面太多,就会请一个无意义的但唯一的字段来代为作主键。

代理键是:

Surrogate (1) – Hall, Owlett and Codd (1976)

一个代理键值确定了外部世界的一个实体。代理键值是数据库生成的,从来不显示给用户或应用程序看。

Surrogate (2) – Wieringa and De Jonge (1991)

一个代理键值确定了数据库中的一个对象。代理键值是数据库生成的,用户或应用程序看不到它。

在实践中,代理键值通常是个自动递增的数字。在Sybase或SQL Server,用identity column标识代理键,PostgreSQL用serial,Oracle用SEQUENCE,在MySQL用标记有AUTO_INCREMENT的字段。

## 何时使用代理键

以中华人民共和国的十八位身份证号为例,从左往右为六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

一家公司想要将它的客户记入数据库,以客户的身份证号作为主键当然是可以的;但是这18位身份证号是用于标识大陆13多亿人口的,一家公司的客户显然没有这么多,所以用18位的数字作为主键有点浪费空间。

另外,身份证号中包含了地区、生日信息,若以身份证号为主键,要不要另开字段记录客户的地区、生日也是个问题。如果不另开字段,从主键(身份证号)中提取地区、生日有点麻烦;如果开字段,主键和地区、生日字段的数据存在冗余。

所以,一般的做法是,根本不记录客户的身份证号(除非有其他需求),用一个代理键作为主键,另开字段记录客户的地区、生日等信息。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容