4 探究Presto SQL引擎-统计计数

作者:vivo互联网用户运营开发团队 -  Shuai Guangying
本篇文章介绍了统计计数的基本原理以及Presto的实现思路 , 精确统计和近似统计的细节及各种优缺点 , 并给出了统计计数在具体业务使用的建议 。
系列文章:
  • 探究Presto SQL引擎(1)-巧用Antlr
  • 探究Presto SQL引擎(2)-浅析Join
  • 探究Presto SQL引擎(3)-代码生成
一、背景学习Hadoop时接触的第一个样例就是word count , 即统计文本中词的数量 。各种BI、营销产品中不可或缺的模块就是统计报表 。在常见的搜索分页模块 , 也需要提供总记录数 。
统计在SQL引擎中可谓最基础、最核心的能力之一 。可能由于它太基础了 , 就像排序一样 , 我们常常会忽视它背后的原理 。通常的计数是非常简单的 , 例如统计文本行数在linux系统上一个wc命令就搞定了 。
除了通常的计数 , 统计不重复元素个数的需求也非常常见 , 这种统计称为基数统计 。对于Presto这种分布式SQL引擎 , 计数的实现原理值得深入研究 , 特别是基数统计 。关于普通计数和基数计数 , 最典型的例子莫过于PV/UV 。
二、基数统计主要算法在SQL语法里面 , 基数统计对应到count(distinct  field)或者aprox_distinct() 。通常做精确计数统计需要用到Set这种数据结构 。通过Set不仅可以获得数量信息 , 还能不重不漏地获取每一个元素 。
Set内部有两种实现实现原理:Hash和Tree 。
在海量数据的前提下 , Hash和Tree有一个致命的问题:内存消耗 , 而且随着数据量级的增长 , 内存消耗也是线性增长 。
面对Set内存消耗的问题 , 通常有两种思路:
  • 一种是选取其他内存占用更小的数据结构 , 例如bitmap;
  • 另一种是放弃精确 , 从数学上寻求近似解 , 典型的算法有Linear Count和HyperLogLog 。
2.1 Bitmap在数据库领域Bitmap并不是新事物 , 一般用作索引 , 称为位图索引 。所谓位图索引 , 就是用一个bit位向量来记录某个字段值是否存在于对应的记录 。它有一个前置条件:记录要有永久的编号 , 类似于从1开始的自增主键 。
2.1.1 位图向量的构建举个例子 , 假设表user记录如下:
4 探究Presto SQL引擎-统计计数

文章插图
这是很典型的一张数据库表 。对于表中的字段 , 如何构建位图索引呢?以age字段为例:
  • S1: 确定字段的取值集合空间:  {30,40,50}  一共3个选项 。
  • S2: 依次为每个选项构建一个长度为6的bit向量 , 得到一个3*6的位图 。3表示字段age的取值基数 , 6表示记录数 。

4 探究Presto SQL引擎-统计计数

文章插图
  • S3:  基于表设置位图相应向量值 。例如:age=30的记录id分别为{1,2,6} , 那么在向量1,2,6位置置为1 , 其他置为0 。得到110001 。

4 探究Presto SQL引擎-统计计数

文章插图
同理 , 对于name字段 , 其向量位图为:
4 探究Presto SQL引擎-统计计数

文章插图
可以看出 , 如果对于数据表的一个字段 , 如果记录数为n且字段的取值基数为m , 那么会得到一个m*n的位图 。

经验总结扩展阅读