count distinct基数统计之一

29 篇文章 0 订阅

最近开发一个业务功能遇到一个关于 count distinct的统计,现在这个统计功能是直接运行在mysql数据库中的。现在mysql执行时间在业务上还是可以容忍的范围内,也没有进行优化。但我感觉有必要将后续的优化方案先整理一下。

随着业务数据量的增加,程序改进思路:

  1. mysql的 count distinct语法

    在数据量不算很大的情况下,对于count distinct统计,我们一般都是在数据库中执行,性能依赖于mysql的配置。我们也只能通过影响其执行计划来进行优化。当数据库的性能我们无法容忍的情况下,需要进行优化。

  2. 单机的数据提取与java.util.HashSet

    通过分页查询将原始数据提取出来,然后通过hashset进行过滤,最后HashSet.size即为统计结果.主要思路如下:

    1.  通过分页查询将单页数据从数据库提取出来,存在list之中;
    2.  处理这个list列表,将结果集存入HastSet;
    3.  重复步骤1,2
    

    整个的这个过程可以使用单线程完成,也可以使用多线程完成,如果使用多线程需要处理HashSet的并发更新。在这方面有现成的框架spring-batch.但是随着数据库的增大,HashSet结果集占用的内存也是不容忽视的。所以大数据量的统计中不能使用。一般情况下是数据提取的性能会先出现。

  3. 多机的数据提取与java.util.BitSet

    这一步的方法与上一步的区别,在于数据提取使用多机+多线程.

    1. 单机数据分片服务器对于原始数据进行分片;
    2. 将分片结果作为参数下发后面的数据处理服务器(有多台);
    3. 数据处理服务器根据分片结果参数,对数据进行分页提取,存入list之中;
    4. 处理这个list列表,将结果集存入java.util.HashSet;
    5. 重复步骤3,4,其中3,4,5这三步是多台数据处理服务器并行执行。
    6. 每台数据处理服务器将最终的结果返回给单机数据分片服务器;
    7. 数据分片服务器完成结果合并,返回最终结果;
    

    这个也依然可以采用spring-batch框架。最终的数据存储使用java.util.BitSet,过程结果集使用java.util.HashSet.使用java.util.BitSet相比java.util.HashSet存储容量会大大缩小。比如我们存储一个Long, 在不考虑HashSet本身占用内存大小,则占用的内存为8byte,而在BitSet中只占1bit,所以大小缩小了64分之一,1亿的基数量,在BitSet中占用的内存大约12.5m。
    如果spring-batch框架,出现在数据提取或处理过程出现性能问题,可以考虑storm框架.当然系统的复杂性则会是更上一层楼。毕竟spring-batch框架是为企业级作批处理的框架;而storm则是作流式处理的框架。二者的性能不可以同日而语。因为我们这里讨论的出发点是数据存储在关系统型数据库mysql中,能够存储在mysql中的数据量,基本上不需要storm框架,spring-batch是可以搞定的( 关于mysql性能,在单表的数据量基本都是千万量级的,再大会有性能问题.上次参加csdn数据库大会时有报告者说mysql在单表主键查询时,数据库可以达到一个亿,但也只限主键查询,一般的数据量2000万~4000万之间)。

思路再发散一下

互联网系统统计一天的uv,其实质也是count distinct, 如果依然采用如上的框架会遇到如下问题:

  • mysql的容量问题,及单机写入性能问题,怎么办?

    在这种情况下,基本使用的都是可以自动扩缩的非关系型数据库Hbase,mongodb等来作为数据的存储容器;

  • 数据处理过程中出现性能怎么办?

    采用可以随时扩容的流式计算框架, 如storm,heron,spark等;之前提的spring-security在数据处理开始之后,是无法扩容的;

  • 合并结果集在单机超出BitSet的容量怎么办,出现了hash碰撞怎么办?

    一句话,数据大到这个量级上,你想要一个精确值也算是一种奢侈了。只能通过算法进行相应的估计, 相关的估计算法有hyperloglog,hyperloglog plus,linear counting,count the estimate,可以直接参见
    https://github.com/zhuzhong/stream-lib.git 中的cardinality部分,寻找相关的paper去了解相应的算法原理。对于这部分内容我也是在学习的路上.后续慢慢将相应的学习笔记补上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值