目录
1. MatrixOne数据库是什么?
2. 哈希表数据结构基础
3. 哈希表基本设计与对性能的影响
3.1 链地址法
3.2 开放寻址法
3.3 碰撞处理
3.4 Max load factor
3.5 Growth factor
3.6 空闲桶探测方法
4. 一些常见的哈希表实现
4.1C++
4.2std::unordered_map/boost::unordered_map
4.3 go map
4.4 swisstable
4.5 ClickHouse的哈希表实现
5. 高效哈希表的设计与实现
5.1 基本设计与参数选择
5.2 哈希函数
5.3 特殊优化
5.4 具体实现代码
6. 性能测试
6.1 测试环境
6.2 测试内容
6.3 整数key结果
6.4字符串key结果
7. 总结
1
MatrixOne数据库是什么?
MatrixOne是一个新一代超融合异构数据库,致力于打造单一架构处理TP、AP、流计算等多种负载的极简大数据引擎。MatrixOne由Go语言所开发,并已于2021年10月开源,目前已经release到0.3版本。在MatrixOne已发布的性能报告中,与业界领先的OLAP数据库Clickhouse相比也不落下风。作为一款Go语言实现的数据库,居然可以与C++实现的顶级OLAP数据库性能媲美,这其中就涉及到了很多方面的优化,包括高性能哈希表的实现,本文就将详细说明MatrixOne是如何用Go实现高性能哈希表的。
Github地址:https://github.com/matrixorigin/matrixone
2
哈希表数据结构基础
哈希表(Hashtable)是一种非常基础的数据结构,对于数据库的分组聚合和Join查询的性能至关重要。以如下的分组聚合为例(备注,图引自参考文献1):
SELECT col, count(*) FROM table GROUP BY col
它包含两个处理阶段:第1阶段是使用数据源的数据建立一个哈希表。哈希表中的每条记录都与一个计数器有关。如果记录是新插入的,相关的计数器被设置为1;否则,计数器被递增。第二阶段是将哈希表中的记录集合成一种可用于进一步查询处理的格式。
对于Join查询而言,以如下SQL为例:
SELECT A.left_col, B.right_col FROM A JOIN B USING (key_col)
它同样也有两个阶段:第一阶段是使用Join语句右侧表的数据建立一个哈希表,第二阶段是从左侧表中读取数据,并快速探测刚刚建立的哈希表。构建阶段与上面的分组实现类似,但每个哈希表的槽位都存储了对右边列的引用。
由此可见,哈希表对于数据库的SQL基础能力起着很关键的作用 ,本文讨论哈希表的基本设计与对性能的影响,比较各种常见哈希表实现,然后介绍我们为MatrixOne实现的哈希表的设计选择与工程优化,最后是性能测试结果。
我们预设读者已经对文中提到哈希表相关的概念有所了解,主要讨论其对性能的影响,不做详细科普。如果对基本概念并不了解,请从其他来源获取相关知识,例如维基百科。
3
哈希表基本设计与对性能的影响
碰撞处理
不同的key经哈希函数映射到同一个桶,称作哈希碰撞。各种实现中最常见的碰撞处理机制是链地址法(chaining)和开放寻址法(open-address