用户可以通过创建 bitmap index 加速查询。
本文档主要介绍如何创建 bitmap 索引,以及创建 bitmap 索引的一些注意事项和常见问题。
名词解释
bitmap 索引:用位图表示的索引,对索引列的每个键值建立一个位图。是一种快速数据结构,能够加快查询速度。
索引原理示意:
原理介绍
主要针对大量相同值的列而创建(例如:类别,操作员,部门 ID,库房 ID 等),索引块的一个索引行中存储键值和起止 Rowid,以及这些键值的位置编码,位置编码中的每一位表示键值对应的数据行的有无。一个块可能指向的是几十甚至成百上千行数据的位置。
当根据键值查询时,可以根据起始 Rowid 和位图状态,快速定位数据。
当根据键值做 and,or 或 in(x,y,..)查询时,直接用索引的位图进行位运算,快速得出结果行数据。
当执行 select count(xx) 时,可以直接访问索引就快速得出统计数据。
语法
创建索引
支持在创建表时就进行 Bitmap 索引指定。
CREATE TABLE create_table_with_bitmap (
l_shipdate date NOT NULL,
l_comment varchar(44) NOT NULL,
INDEX shipdate_bm_index (l_shipdate) USING BITMAP COMMENT 'shipdate bitmap index'
) ENGINE=OLAP
DUPLICATE KEY(l_shipdate)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(l_shipdate) BUCKETS 96
PROPERTIES (
"replication_allocation" = "tag.location.default: 3",
"in_memory" = "false",
"storage_format" = "V2",
"disable_auto_compaction" = "false"
);
也支持对现有的表进行修改增加某一列的 Bitmap 索引,例如在 table1 上为 siteid 创建 Bitmap 索引:
CREATE INDEX [IF NOT EXISTS] index_name ON table1 (siteid) USING BITMAP COMMENT 'balabala';
查看索引
展示指定 table_name 的下索引:
SHOW INDEX FROM example_db.table_name;
删除索引
删除指定 table_name 的下索引:
DROP INDEX [IF EXISTS] index_name ON [db_name.]table_name;
基本原理
腾讯云数据仓库 TChouse-D 使用的是列存储, 在没有索引的情况下,要判断某列F是否与某个值 V 相等,只能遍历一整列所有的数据,才能得到与 V 相等的行号。Bitmap 索引为了避免检索时对所有数据进行遍历,在原来列存数据的基础上,顺序保存列所有的值(有序字典),以及每个值对应的行号。这样在检索时,就可以通过值,快速查找到等于这个值的所有行号。
例如一列数据为[x, x, y, y, y, z, y, x, z, x],一共包含10行,则该列数据的 Bitmap 索引的有序字典为{x, y, z}, x、y、z对应的位图分别为:
x的位图: [0, 1, 7, 9]
y的位图: [2, 3, 4, 6]
z的位图: [5, 8]
注意事项
目前索引命令([show | create | drop] index)仅支持 bitmap 类型的索引。
bitmap 索引仅在单列上创建。
bitmap 索引能够应用在 Duplicate
、Uniq
数据模型的所有列和 Aggregate
模型的 key 列上。
bitmap 索引支持的数据类型如下:
TINYINT
SMALLINT
INT
BIGINT
CHAR
VARCHAR
DATE
DATETIME
LARGEINT
DECIMAL
BOOL
bitmap 索引仅在 Segment V2 下生效。当创建 index 时,表的存储格式将默认转换为 V2 格式(查看表的存储格式可通过 show create table table_name 命令)。
bitmap 索引适用场景
适用于低基数的列上,建议在100到100,000之间,如:职业、地市等。重复度过高则对比其他类型索引没有明显优势;重复度过低,则空间效率和性能会大大降低。
特定类型的查询例如 count、or、and 等逻辑操作因为只需要进行位运算。如:通过多个条件组合查询,select count(*) from table where job = '医生' and phonetype = 'iphone' and gender ='男';
类似这种场景,如果在每个查询条件列上都建立了 bitmap 索引,则数据库可以进行高效的位运算,精确定位到需要的数据,减少磁盘 IO。并且筛选出的结果集越小,bitmap 索引的优势越明显。
适用于即席查询、多维分析等 OLAP 场景。如果有一张表有100列,用户会使用其中的20个列作为查询条件(任意使用这20个列上的N的列),几乎没有办法创建合适的 b-tree 索引。但是在这些列上创建20个 bitmap 索引,那么所有的查询都可以应用到索引。
Bitmap索引支持等值查询和范围查找,支持= , < , <= ,> ,>= 表达式。
bitmap 索引不适用场景
值重复度低的列,如:身份证号、手机号码等。
重复度过高的列,如:性别,可以建立 bitmap 索引,但不建议单独作为查询条件使用,建议与其他条件共同过滤。
经常需要更新修改的列。
最佳实践
以下基于 TPCH 测试集的 lineitem 表(6亿条记录), 构建 Bitmap 索引和使用。
假设对于 lineitem 表,预期优化以下 sql,优化前耗时约为900ms。
select l_quantity,l_returnflag,l_commitdate from lineitem where l_suppkey = 'xxx';
分析是否适用 Bitmap 索引
查询条件 l_suppkey,此时并不命中前缀索引也没有其他索引。l_suppkey 字段类型为INT ,为可以使用 Bitmap 索引的类型。
查看 l_suppkey 这一列的取值基数,在6亿数据表上,l_suppkey 的取值为100W,取值基数并没有特别高,这里尝试使用 Bitmap 索引进行优化。
创建 Bitmap 和等待索引构建
创建 Bitmap 索引:
create index suppkey_bitmap_index on lineitem(l_suppkey) using bitmap comment 'test';
通过 show alter table column 命令查看索引构建进度:
通过 show create table lineitem 命令查看 lineitem 表存在的索引:
对比优化前后效果
优化后,耗时40ms。
优化前,耗时240ms(这里使用的 lineitem2 表是 lineitem 表的备份,数据量和表结构一致)。
常见问题
select count(*) 对 Bitmap 索引列生效吗?
生效,通过查看对 select count(*) from lineitem where l_suppkey = '388041';
语句的profile,可以看到 RowsBitmapIndexFiltered 字段帮助过滤了大量数据。
RowsBitmapIndexFiltered: 200.01525M (200015250)
列的取值基数比较大,为什么不适合使用 bitmap 索引?
实测对6亿记录的 lineitem 的 l_partkey 列(2000W取值)进行 bitmap 索引构建。优化前点查耗时600ms,优化后点查耗时为120ms。效率提升了5倍。可见对基数高的列建立索引,查询也能带来效率提升。
但是存储消耗比较大。lineitem 表6亿数据3副本占用约62G存储,对 l_partkey 列构建完 bitmap 索引后,lineitem 表存储涨到95G。理论上,bitmap 索引构建增长的存储,在未压缩情况,为 2000W(取值)* 60000W(行数)bit。
可见对高基数列构建 bitmap 索引,性价比并不高,这个时候更推荐 bloomfilter 索引。
本页内容是否解决了您的问题?