发明内容
为了克服现有Oceanbase的SQL查询方法中不支持嵌套查询的不足,本发明提供一种面向海量分布式数据库的嵌套查询方法。该方法采用Bloomfilter和HashMap的两阶段过滤方法来应对大数据量查询,通过构建查询树和查询引擎实现嵌套子查询功能。在小数据集查询时,直接绑定子查询结果集到物理计划。当大数据量查询时,启用两 阶段过滤策略,使用BloomFilter在ChunkServer上进行初次过滤,过滤后的数据在MergeServer进行二次精确匹配,并采用HashMap来存储需要对比的结果集,保证一次过滤后的数据能快速找到匹配的数据行。由于BloomFilter能快速过滤掉大量无关数据,而HashMap又能快速匹配符合条件的结果集。因此,本发明方法在实现了嵌套查询的基础上,大大提高了SQL查询速度。
本发明解决其技术问题所采用的技术方案是:一种面向海量分布式数据库的嵌套查询方法,其特点是采用以下步骤:
步骤一、采用关系型数据库的SQL语句解析结果构建查询树:
查询树的节点数据结构如下:
其中,phy内保存子节点执行结果填充位置标记;phy内的位置标记与next_child一一对应。
步骤二、为查询树构建执行引擎;根据查询树的特性,采用从叶节点到根节点的递归计算算法。
递归算法如下:
串行执行每个节点;除根节点外,每个节点执行结束,将本节点从查询树移除,以确保查询树的正确执行。
算法中的threshold控制着是否启用HashMap和Bloomfilter。threshold为可变参数,可变化范围为(0,511]。
当子查询结果集不大于threshold时,直接将子查询结果集写入主查询的物理计划内,接下来的物理计划执行等处理遵循OceanBase现有的查询处理。当子查询结果集大于threshold时,将主查询的物理计划同子查询结果集生成的Bloomfilter一起发送至Chunkserver处理,MergeServer利用子查询结果集生成的HashMap过滤获取的结果集。
步骤三、首先ChunkServer进行非严格的BloomFiter过滤,获得最终结果集的超集;其次MergeServer进行严格的HashMap过滤,获得最终结果集。
I、BloomFilter过滤。
分布式架构下,将作为主查询过滤条件的超大的子查询结果集分发至不同的数据节点的方案会占用大量传输带宽。为了降低带宽占用率且加速查找,采用多哈希函数映射的快速查找数据结构--布隆过滤器:BloomFilter。
策略所构建的BloomFilter采用如下的公式:
k=-ln(p)÷ln(2)
m=(n*k)÷ln(2)
式中,p是误判率,m是位数组大小,n是总数据数目,k是所需哈希函数数目。
BloomFilter的构建由MergeServer负责,构建算法如下:
Input:子查询结果集S//S代表子查询结果集
①依据上述公式及S、默认误报率p,计算BloomFilter所需位数组大小m,所需哈希函数数目k;
②读取S的一条记录R,如果R为NULL,转⑤;//R代表结果集中的一条记录,NULL代表一条空记录。
③将R依次带入k个哈希函数H1(R),...,Hk(R)得到k个值V1,...,Vk。//H1(R),...H1(K)代表k个哈希函数,V1,...Vk代表k个哈希函数的值。
④将BloomFilter的位数组的V1,...,Vk位设置为True,转②;
⑤构建结束,返回BloomFilter。
BloomFilter的查找算法如下:
①读入一条记录R
②将R依次带入k个哈希函数H1(R),...,Hk(R)得到k个值V1,...,Vk。
③比对BloomFilter的位数组的V1,...,Vk位。如果k个位全为True,则返回查找成功,否则返回查找失败。
II、HashMap过滤。
MergeServer严格的数据过滤条件是海量的子查询结果集,采用全内存的HashMap存储子查询结果集。
HashMap的高效查找依赖于哈希函数的均匀散列和低冲突率。均匀散列保证每一个桶内的数据检索时间大致相同;低冲突率保证快速定位,采用链表法解决地址冲突。链表的每一个节点的只有key。
MergeServer负责构建HashMap,且利用构建的HashMap进行严格的数据过滤。
HashMap的构建算法如下:
Input:子查询结果集S
①初始化HashMap,分配哈希桶空间;
②读取S的一条记录R,如果R为NULL,转⑤;
③将R带入哈希函数H(R),依据得到的哈希值确定待插入的哈希桶BUCKETBT。
④将R以链表的形式挂在BT的链表末尾,转②;
⑤构建结束,返回HashMap。
HashMap的查找算法如下:
①读入一条记录R
②将R带入哈希函数H(R),依据得到的哈希值确定待查询的哈希桶BUCKETBT。//BT代表一个哈希桶。
③遍历BT内的链表节点,逐个比对。如果相同则返回查找成功,否者返回查找失败。
查询树的每一个非叶子节点的执行都需要两阶段数据过滤,即首先根据孩子节点的结果集构建HashMap和BloomFilter,接着将BloomFilter同本节点的物理计划分发至数据节点,数据节点依据物理计划及过滤条件BloomFilter,将最终结果集的超集返回给MergeServer,最后MergeServer利用HashMap执行最后的严格的数据过滤,获得最终结果集。
本发明的有益效果是:该方法采用Bloomfilter和HashMap的两阶段过滤方法来应对大数据量查询,通过构建查询树和查询引擎实现嵌套子查询功能。在小数据集查询时,直接绑定子查询结果集到物理计划。当大数据量查询时,启用两阶段过滤策略,使用BloomFilter在ChunkServer上进行初次过滤,过滤后的数据在MergeServer进行二次精确匹配,并采用HashMap来存储需要对比的结果集,保证一次过滤后的数据能快速找到匹配的数据行。由于BloomFilter能快速过滤掉大量无关数据,而HashMap又能快速匹配符合条件的结果集。因此,本发明方法极大的改善了OceanBase的查询性能,提高了大数据集的查询速度。
下面结合附图和具体实施方式对本发明作详细说明。
具体实施方式
参照图1-2。本发明面向海量分布式数据库的嵌套查询方法具体步骤如下:
A、构建查询树:
策略没有采用传统关系数据库的SQL重写技术,而是采用“内查询先执行,外查询绑定内查询的结果(集)后执行”的方案。该方案实现简便,而且相较于SQL重写技术,降低了传送到MergeServer的数据量,节省了带宽,减小了嵌套查询对并发查询的影响。
对于如下的嵌套查询SQL:
Select X.a from X WHERE X.b in(Select Y.b from Y)[AND/OR]
X.c in(select C.c from C WHERE C.d in(Select D.d from D)),
主查询有一个(Select X.a from X WHERE X.b in...),用Q1来表示,子查询有3个,(Select Y.b from Y)用Q2来表示,(select C.c from C WHERE C.d in...)用Q3来表示,(Select D.d from D)用Q4来表示。Q1的结果集依赖于Q2和Q3的查询结果,Q3的结果集依赖于Q4的查询结果,Q2和Q3的结果集并列,因此形成了图1所示的查询树。
查询树的节点的部分主要数据结构如下:
备注:phy内保存子节点执行结果填充位置标记;phy内的位置标记和next_child一一对应。
查询树可以借助传统关系型数据库的SQL语句解析结果进行构建。
B、构建查询树的执行引擎:
执行引擎的主要功能就是按照一定的策略执行查询树。依据策略构建的查询树,具有“兄弟节点相互独立”和“父节点依赖子节点”的特性。查询引擎根据查询树的特性,采用从叶节点到根节点的递归计算算法。
递归算法如下:
算法的核心:串行执行每个节点;除根节点外,每个节点执行结束,将本节点从查询树移除,以确保查询树的正确执行。
算法中的threshold控制着是否启用HashMap和Bloomfilter。threshold为可变参数,可变化范围为(0,511],因为OceanBase的操作符支持的操作数上限不大于511组。
当子查询结果集不大于threshold时,直接将子查询结果集写入主查询的物理计划内,接下来的物理计划执行等处理遵循OceanBase现有的查询处理。当子查询结果集大于threshold时,将主查询的物理计划同子查询结果集生成的Bloomfilter一起发送至Chunkserver处理,MergeServer利用子查询结果集生成的HashMap过滤获取的结果集。
C、两阶段数据过滤:
查询引擎构造完成后,将查询条件传给ChunkServer,进行两阶段数据过滤过程。
首先ChunkServer进行非严格的BloomFiter过滤,获得最终结果集的超集;其次MergeServer进行严格的HashMap过滤,获得最终结果集。
I、BloomFilter过滤。
分布式架构下,将作为主查询过滤条件的超大的子查询结果集分发至不同的数据节点的方案会占用大量传输带宽。为了降低带宽占用率且加速查找,嵌套查询策略使用了一种多哈希函数映射的快速查找数据结构--布隆过滤器:BloomFilter。相较于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势,特别适合于海量数据集的表示和查找。
策略所构建的BloomFilter采用如下的公式:
k=-ln(p)÷ln(2)
m=(n*k)÷ln(2)
p:误判率,m:位数组大小,n:总数据数目,k:所需哈希函数数目。
BloomFilter的构建由MergeServer负责,构建算法如下:
Input:子查询结果集S
①依据上述公式及S、误报率P(默认),计算BloomFilter所需位数组大小m,所需哈希函数数目k;
②读取S的一条记录R,如果R为NULL,转⑤;
③将R依次带入k个哈希函数H1(R),...,Hk(R)得到k个值V1,...,Vk。
④将BloomFilter的位数组的V1,...,Vk位设置为True,转②;
⑤构建结束,返回BloomFilter。
BloomFilter的查找算法如下:
①读入一条记录R
②将R依次带入k个哈希函数H1(R),...,Hk(R)得到k个值V1,...,Vk。
③比对BloomFilter的位数组的V1,...,Vk位。如果k个位全为True,则返回查找成功,否则返回查找失败。
ChunkServer进行数据表扫描时,每读取一行,都执行BloomFilter检查,检查通过则发送至MergeServer,否则继续读取下一行,直至读取完毕。
II、HashMap过滤。
由于BloomFilter的误报特性,MergeServer得到的是最终结果集的超集。因此MergeServer必须进行严格的数据过滤,以获得最终结果集。
MergeServer严格的数据过滤条件就是海量的子查询结果集。如何组织子查询结果集,以提供高效的查找是一个关乎性能的重要问题。在当今服务器普遍支持大内存的状况下,嵌套查询策略采用全内存的HashMap存储子查询结果集。
HashMap的高效查找依赖于哈希函数的均匀散列和低冲突率。均匀散列保证每一个桶内的数据检索时间大致相同;低冲突率保证快速定位。本策略设计的HashMap采用链表法解决地址冲突。链表的每一个节点的只有key。
MergeServer负责构建HashMap,且利用构建的HashMap进行严格的数据过滤。
HashMap的构建算法如下:
Input:子查询结果集S
①初始化HashMap,分配哈希桶空间;
②读取S的一条记录R,如果R为NULL,转⑤;
③将R带入哈希函数H(R),依据得到的哈希值确定待插入的哈希桶BUCKET BT。
④将R以链表的形式挂在BT的链表末尾,转②;
⑤构建结束,返回HashMap。
HashMap的查找算法如下:
①读入一条记录R
②将R带入哈希函数H(R),依据得到的哈希值确定待查询的哈希桶BUCKET BT。
③遍历BT内的链表节点,逐个比对。如果相同则返回查找成功,否者返回查找失败。
MergeServer对ChunkServer发送来的每一条数据,都执行HashMap过滤,将过滤生成的结果返回给用户。因为BloomFilter的固有的误报特性,ChunkServer发送给MergeServer的是包含最终结果集的超集,因此MergeServer必须进行一次严格过滤,进行精确匹配,去除误报记录,获取最终结果。
查询树的每一个非叶子节点的执行都需要两阶段数据过滤,即首先根据孩子节点的结果集构建HashMap和BloomFilter,接着将BloomFilter同本节点的物理计划分发至数据节点,数据节点依据物理计划及过滤条件BloomFilter,将最终结果集的超集返回给MergeServer,最后MergeServer利用HashMap执行最后的严格的数据过滤,获得最终结果集。
下面通过实验说明本发明方法的效果。
实验环境:Oceanbase单服务器部署。服务器由1T硬盘,16G内存,16核CPU,一块网卡组成。服务器操作系统是Red Hat6.2,内核是2.6.32-220.el6.x86_64。
6.1实验一。
实验一衡量小规模子查询数据集状况下嵌套子查询策略的性能。测试表test,共计100万条记录,包含id、name共计两个字段,其中id为主键列。启用BloomFilter和HashMap的阈值设置为20,即子查询结果集不大于20条。
测试SQL语句模板如下所示。
一层嵌套SQL:Select count(*)from test where[id/name]in(select[id/name]from test Where id<ConstValue)
小规模子查询数据集下,无主键索引的OceanBase已有查询策略性能测试结果及嵌套查询策略性能测试结果如表1所示。嵌套查询SQL已转化为OceanBase支持的非嵌套SQL。
表1小规模子查询数据集下两种策略的结果,无主键索引
表1结果表明:随着数据量的增加,嵌套子查询的性能远远高于Oceanbase现有的非主键列的查询性能。
6.2实验二。
实验二衡量大规模子查询数据集状况下嵌套子查询策略的性能。实验环境同实验一。大规模子查询数据集下的嵌套查询策略的性能测试结果及mysql5.1.52的性能测试结果如表2所示。
表2大规模子查询数据集下嵌套查询策略的结果
表3验证了嵌套子查询的高性能,在同等条件下,其耗时远远低于Mysql耗时。