位图索引Bitmap

本文为您介绍Hologres中位图索引Bitmap的使用相关内容。

Bitmap介绍

在Hologres中,bitmap_columns属性指定位图索引,是数据存储之外的独立索引结构,以位图向量结构加速等值比较场景,能够对文件块内的数据进行快速的等值过滤,适用于等值过滤查询的场景。使用语法如下。

-- Hologres V2.1版本起支持的语法
CREATE TABLE <table_name> (...) WITH (bitmap_columns = '[<columnName>{:[on|off]}[,...]]');

-- 所有版本支持的语法
CREATE TABLE <table_name> (...);
CALL set_table_property('<table_name>', 'bitmap_columns', '[<columnName>{:[on|off]}[,...]]');

参数

说明

table_name

表名称。

columnName

列名称。

on

当前字段打开位图索引。

off

当前字段关闭位图索引。

使用建议

  • 适合将等值查询的列设置为Bitmap,能够快速定位到符合条件的数据所在的行号。但需要注意的是Bitmap对于基数比较高(重复数据较少)的列会有比较大的额外存储开销。

  • 不建议为每一列都设置Bitmap,不仅会有额外存储开销,也会影响写入性能(因为要为每一列构造Bitmap)。

  • 不建议为实际内容为JSON,但保存为text类型的列设置Bitmap。

使用限制

  • 只有列存表和行列共存表支持设置Bitmap,行存表不支持设置。

  • Bitmap指定的列可以为空。

  • 当前版本默认所有TEXT类型的列都会被隐式地设置为Bitmap。

  • 设置位图索引命令可以在事务之外单独使用,表示修改位图索引列,修改之后非立即生效,比特编码构建和删除在后台异步执行,详情请参见ALTER TABLE

  • bitmap_columns属性仅支持设为onoff,Hologres V2.0版本起,不支持将bitmap_columns属性设为auto

技术原理

Bitmap不同于Distribution Key和Clustering Key,Bitmap是数据存储之外的独立索引,设置了Bitmap索引之后,系统会将列对应的数值生成一个二进制字符串,用于表示取值所在位置的Bitmap,当查询命中Bitmap时,会快速定位到数据所在的行号(Row Number),从而快速过滤出数据。但Bitmap并不是没有开销的,对于以下场景需要注意事项如下:

  • 列的基数较高(重复数据较少)场景:假如列的基数较高,那么就会为每一个值生成一个Bitmap,当非重复值很多的时候,就会形成稀疏数组,占用存储较多。

  • 大宽表的每一列都设置为Bitmap场景:如果为大宽表的每一列都设置为Bitmap,那么在写入时每个值都需要构建成Bitmap,会有一定的系统开销,从而影响写入性能。

综上,Bitmap本质上是空间换时间的手段,对于数据分布比较均匀的列有比较高的性价比。位图索引

如下示例,可以通过explain SQL查看是否命中Bitmap索引。在执行计划中,有Bitmap Filter则说明命中Bitmap索引。

  • V2.1版本起支持的语法:

    CREATE TABLE bitmap_test (
        uid int NOT NULL,
        name text NOT NULL,
        gender text NOT NULL,
        class text NOT NULL,
        PRIMARY KEY (uid)
    )
    WITH (
        bitmap_columns = 'gender,class'
    );
    
    INSERT INTO bitmap_test VALUES 
    (1,'张三','男','一班'),
    (2,'李四','男','三班'),
    (3,'王五','女','二班'),
    (4,'赵六','女','二班'),
    (5,'孙七','男','二班'),
    (6,'周八','男','三班'),
    (7,'吴九','女','一班');
    
    explain SELECT * FROM bitmap_test where gender='男' AND  class='一班';
  • 所有版本支持的语法:

    begin;
    create table bitmap_test (
      uid int not null,
      name text not null,
      gender text not null,
      class text not null,
      PRIMARY KEY (uid)
    );
    call set_table_property('bitmap_test', 'bitmap_columns', 'gender,class');
    commit;
    
    INSERT INTO bitmap_test VALUES
    (1,'张三','男','一班'),
    (2,'李四','男','三班'),
    (3,'王五','女','二班'),
    (4,'赵六','女','二班'),
    (5,'孙七','男','二班'),
    (6,'周八','男','三班'),
    (7,'吴九','女','一班');
    
    explain SELECT * FROM bitmap_test where gender='男' AND  class='一班';

如下所示执行计划结果中有Bitmap Filter算子,说明命中Bitmap索引。执行计划

Bitmap和Clustering Key的区别

  • 相同点:

    Bitmap和Clustering Key都是文件内的数据过滤。

  • 不同点:

    Bitmap更适合等值查询,通过文件号定位到数据;Clustering Key是文件内的排序,因此更适合范围查询。

    Clustering Key的优先级会比Bitmap更高,即如果为同一个字段设置了Clustering Key和Bitmap,那么优化器会优先使用Clustering Key去匹配文件,示例如下:

    • V2.1版本起支持的语法:

      --设置uid,class,date 3列为clustering key,text列设置默认为bitmap
      
      CREATE TABLE ck_bit_test (
          uid int NOT NULL,
          name text NOT NULL,
          class text NOT NULL,
          date text NOT NULL,
          PRIMARY KEY (uid)
      )
      WITH (
          clustering_key = 'uid,class,date',
          bitmap_columns = 'name,class,date'
      );
      INSERT INTO ck_bit_test VALUES 
      (1,'张三','1','2022-10-19'),
      (2,'李四','3','2022-10-19'),
      (3,'王五','2','2022-10-20'),
      (4,'赵六','2','2022-10-20'),
      (5,'孙七','2','2022-10-18'),
      (6,'周八','3','2022-10-17'),
      (7,'吴九','3','2022-10-20');
    • 所有版本支持的语法:

      --设置uid,class,date 3列为clustering key,text列设置默认为bitmap
      begin;
      create table ck_bit_test (
        uid int not null,
        name text not null,
        class text not null,
        date text not null,
        PRIMARY KEY (uid)
      );
      call set_table_property('ck_bit_test', 'clustering_key', 'uid,class,date');
      call set_table_property('ck_bit_test', 'bitmap_columns', 'name,class,date');
      commit;
      
      INSERT INTO ck_bit_test VALUES
      (1,'张三','1','2022-10-19'),
      (2,'李四','3','2022-10-19'),
      (3,'王五','2','2022-10-20'),
      (4,'赵六','2','2022-10-20'),
      (5,'孙七','2','2022-10-18'),
      (6,'周八','3','2022-10-17'),
      (7,'吴九','3','2022-10-20');
    • 查询uid,class,date 三列,SQL符合左匹配特征,都命中Clustering Key,即使是等值查询也走Clustering Key,而不是走Bitmap。

      SELECT * FROM clustering_test WHERE uid = '3' AND class ='2' AND date > '2022-10-17';

      如下所示执行计划结果中有Cluster Filter算子,没有Bitmap Filter算子,说明查询走Clustering Key,而不是走Bitmap。执行计划2

    • 查询uid,class,date 三列,但class是范围查询,根据左匹配原则,SQL里匹配到>或者<则停止左匹配,那么date因不满足左匹配原则,就不会命中Clustering Key。date设置了Bitmap,则会使用Bitmap。

      SELECT * FROM clustering_test WHERE uid = '3' AND class >'2' AND date = '2022-10-17';

      如下所示执行计划结果中有Cluster Filter算子,说明查询uid,class走走Clustering Key;有Bitmap Filter算子,说明查询date走Bitmap。执行计划3

使用示例

  • V2.1版本起支持的语法:

    CREATE TABLE tbl (
        a text NOT NULL,
        b text NOT NULL
    )
    WITH (
        bitmap_columns = 'a:on,b:off'
    );
    
    -- 修改bitmap_columns
    ALTER TABLE tbl SET (bitmap_columns = 'a:off');--ALTER TABLE语法仅支持全量修改
  • 所有版本支持的语法:

    --创建tbl并设置bitmap索引
    begin; create table tbl (
      a text not null,
      b text not null
    );
    call set_table_property('tbl', 'bitmap_columns', 'a:on,b:off');
    commit;
    
    
    --修改bitmap索引
    call set_table_property('tbl', 'bitmap_columns', 'a:off');--全量修改,将a字段的bitmap都关闭
    call update_table_property('tbl', 'bitmap_columns', 'b:off');--增量修改,将b字段的bitmap关闭,a保留