Postgresql Bitmapset

BitMap

前言

Bitmap的基本思想就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。

原理

bitmap就是使用bit位的值0或1标识一个数是否存在,0表示存在,1则表示不存在

如何使用bitmap表示一个数?

根据上述的实现原理可知,每一位表示一个数,0表示不存在,1表示存在。例如:{1,2,4,6}这几个数怎么在bitmap中表示?

计算机内存分配的最小单位是字节,也就是8位,那如果要表示{12,13,15}怎么办呢?当然是在另一个8位上表示了: 1个int占32位,那么只需要申请一个int数组长度为 int tmp[1+N/32] 即可存储,其中N表示要存储的这些数中的最大值,于是乎:

tmp[0]:可以表示0-31

tmp[1]:可以表示32-63

tmp[2]:可以表示64~95

给定任意整数M,那么M/32就得到下标,M%32就知道它在此下标的哪个位置

bitmap操作

添加元素

怎么把一个数添加到bitmap中呢?例如,想把5这个数字添加到bitmap? 首先,5/32=0,5%32=5,也是说它应该在tmp[0]的第5个位置,那我们把1向左移动5位,然后按位或: 相当于:86 | (1<<5) = 118 ---> b[0] = b[0] | (1<<5)

也就是说,要想插入一个数,将1左移带代表该数字的那一位,然后与原数进行按位或操作 化简一下,就是 86 + (5/8) | (1<<(5%8)) 因此,公式可以概括为: p + (i/8)|(1<<(i%8)) 其中,p表示现在的值,i表示待插入的数.

删除元素

通过上面的章节知道如何向bitmap中添加元素,那么如何删除一个元素呢?我们只需要执行和添加元素相反的操作就可以了。例如从bitmap中删除元素6,首先,6/32=0,6%32=6,也是说它应该在tmp[0]的第6个位置,那我们把1向左移动5位,然后按位与

查找元素

bitmap中每一位代表一个数字,1表示有(或者说存在),0表示无(或者说不存在)。通过把该位设置为1或者0来达到添加和清除的目的,那么判断一个数存不存在就是判断该数所在的位是0还是1 假设,我们想知道3在不在,那么只需判断 b[0] & (1<<3) 如果这个值是0,则不存在,如果是1,就表示存在。

Bitmap的使用场景

快速排序

根据Bitmap实现的原理可知,要想对一组数字进行排序时只需要将待排序的数字添加到bitmap中即可,然后遍历一遍bitmap获取的数据就是排序完成后的结果,时间复杂度为O(n)。

要求排序的数据不能存在重复值以及在大量密集数据情况下才能体现出来优势

快速去重

根据bitmap实现原理可以简单实现数据的去重,只需要将数据添加到bitmap中,相同的元组自然不会被重复添加到bitmap中,添加完成后,遍历bitmap取出数据就是去重后的结果。

快速查找

int数组中的一个元素是4字节占32位,那么除以32就知道元素的下标,对32求余数(%32)就知道它在哪一位,如果该位是1,则表示存在。

postgresql中的Bitmapset

c 复制代码
typedef struct Bitmapset
{
    int nwords; /* number of words in array */ 
    bitmapword words[FLEXIBLE_ARRAY_MEMBER]; /* really [nwords] */ 
} Bitmapset;

postgresql中定义了相关的Bitmapset操作函数。bitmapset.h和bitmapset.c

查看Bitmapset中的元素

Bitmapset在内核代码中经常使用到,通过gdb调试程序时可能需要查看bitmapset内容,经过前面章节介绍应该了解bitmap实现的原理了,那么我们就可以知道如何查看bitmapset中的元素了。下面通过调试一个简单的UPDATE语句分析如果查看bitmapset中的元素: update t1 set a = 2;

  • 堆栈信息:
  • 添加完需要UPDATE权限的列 attno

    相应的数字添加到bitmapset中,直接查看words的值不能直观的体现出来,那么可以通过gdb二进制格式显示:

    从右到左数1是第8位(0开始),那么数字8被添加到bitmapset

附录

位运算

在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方,右移一位相当于除2,右移n位相当于除以2的n次方。

  • << 左移,相当于乘以2的n次方,例如:1<<6 相当于1×64=64,3<<4 相当于3×16=48
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> > > >> </math>>> 右移,相当于除以2的n次方,例如:64>>3 相当于64÷8=8
  • ^ 异或,相当于求余数,例如:48^32 相当于 48%32=16
相关推荐
数分大拿的Statham6 小时前
PostgreSQL中的regexp_split_to_table函数详解,拆分字段为多行
大数据·数据库·postgresql·数据分析·数据清洗
mqiqe6 小时前
PostgreSQL主备环境配置
数据库·postgresql
mqiqe6 小时前
PostgreSQL 容器安装
数据库·postgresql
hai4117419627 小时前
mysql 与postgresql 的区别(gpt4)
数据库·mysql·postgresql
MinIO官方账号10 小时前
从 HDFS 迁移到 MinIO 企业对象存储
人工智能·分布式·postgresql·架构·开源
mqiqe13 小时前
PostgreSQL 基础操作
数据库·postgresql·oracle
Z_W_H_1 天前
【PostgreSQL】安装及使用(Navicat/Arcgis),连接(C#)
数据库·postgresql
小怪兽ysl2 天前
【GBase 8c V5_3.0.0 分布式数据库常用几个SQL】
数据库·postgresql
言成言成啊3 天前
PostgreSQL维护——解决索引膨胀和数据死行
数据库·postgresql
文牧之3 天前
PostgreSQL的walsender和walreceiver进程介绍
运维·数据库·postgresql