索引配置详解
1、Primary Key
在“元数据管理“中,展开“已登录实例”中相应数据库的表,右击,选择 "新建内部表 ",输入表名和字段名,勾选需要添加为主键的字段,点击右上角的“提交”。
若只有Primary Key,建议“属性”中改为“行存”,可提高查询速度
建表完成后,也可以在““DDL语句””中看到Primary Key的配置
2、Distribution Key
在“元数据管理“中,展开“已登录实例”中相应数据库的表,右击,选择 "新建内部表 ",输入表名和字段名
若需要配置主键,可进行勾选
在属性中,选择“分布列”,点击右上角的“提交”。
建表完成后,也可以在“DDL语句”中看到Distribution Key的配置
3、Clustering Key
在“元数据管理“中,展开“已登录实例”中相应数据库的表,右击,选择 "新建内部表 ",输入表名和字段名
若需要配置主键,可进行勾选
在属性中,选择“聚簇列”,点击右上角的“提交”。若配置多个字段,按从左到右的顺序依次排序。
建表完成后,也可以在“DDL语句”中看到Clustering Key的配置
4、Bitmap Columns
在“元数据管理“中,展开“已登录实例”中相应数据库的表,右击,选择 "新建内部表 ",输入表名和字段名
在属性中,将“位图列”设置为“on",点击右上角的“提交”。
建表完成后,也可以在“DDL语句”中看到Bitmap Columns的配置
5、Segment Key
在“元数据管理“中,展开“已登录实例”中相应数据库的表,右击,选择 "新建内部表 ",输入表名和字段名
在属性中,勾选“分段列”,点击右上角的“提交”。
建表完成后,也可以在“DDL语句”中看到Segment Key的配置
6、Dictionary Encoding
在“元数据管理“中,展开“已登录实例”中相应数据库的表,右击,选择 "新建内部表 ",输入表名和字段名
在属性中,将:字典编码列“设置为“on”,点击右上角的“提交”。
建表完成后,也可以在“DDL语句”中看到Dictionary Encoding的配置
索引综合对比
索引类型 | 是****否需要在建表时声明 | 原理 | 建议 | 适合的查询 | 使用限制 |
---|---|---|---|---|---|
Primary Key | 是 | 可以通过Primary Key在主键索引文件中快速定位到RID和Clustering Key,再通过RID和Clustering Key定位到数据所在的文件 | ● 主键的设置尽量选择含有实际业务意义的key,不建议使用serial类型的key设置为主键。 ● 如果表只有基于主键的查询,建议将表设置为行存储,查询性能更好。 | select sum(a) from tb1 where a > 100 and a < 200; select sum(a) from tb1 where a = 100 ; | ● 被设置为primary key的字段是唯一且非空的列或者列组合,同时只能在一个语句里设置多列为表的primary key。 ● 目前primary key不支持Float、Double、Numeric、Array、Json、Date及其他复杂数据类型,不支持修改主键,如需修改主键请重新建表。从V1.3.22及以上版本支持将Date类型设为主键, ● 如果是分区表,且设置了主键,那么分区键必须是主键的一部分。 ● 行存表必须设置主键,行列共存表必须设置主键,列存表不要求有主键。 ● 不支持修改主键,如需修改主键请重新建表。 |
Distribution Key | 是 | 数据会根据Distribution Key被分配到各个shard上,算法为Hash(distribution_key)%shard_count,结果为对应的shard。系统会保证distribution_key相同的记录会被分配到同一个shard上。 | ● Distribution Key尽量选择分布均匀的key,否则容易因为数据倾斜导致负载倾斜,使得查询效率变低 ● 选择Group by频繁的列作为Distribution Key ● join 场景中,设置join key为Distribution Key,避免数据shuffle,实现local join。同时要join的表需要在同一个table group。 ● 不建议为一个表设置多个Distribution Key,建议不超过2列,设置多列为Distribution Key,查询是若没有全部命中,则容易出现数据shuffle。 | select sum(a) from tb1 where a > 100 and a < 200; select sum(a) from tb1 where a = 100 ; select a,sum(b) from agg_tbl group by a; select * from tbl1 join tbl2 on tbl1.a=tbl2.c; SELECT * FROM join_tbl1 INNER JOIN join_tbl2 ON join_tbl2.a = join_tbl1.a INNER JOIN join_tbl3 ON join_tbl2.a = join_tbl3.a; | ● 需要建表时设置Distribution Key,建表后修改Distribution Key需要重新建表并导数据。 ● 可以支持单列或者多列设置为Distribution Key,指定列时部分如设置单列,不要有多余空格。如设置多个列,则以逗号分隔,同样不要有多余的空格,指定多列为Distribution Key时,列的顺序不影响数据的布局和查询性能。 ● 不支持float/double/numeric/array/json及其他复杂数据类型。 ● 如果表有设置主键(PK),那么Distribution Key必须为PK或者PK中的部分字段(不能为空,即不指定任何列),因为要求同一记录的数据只能属于一个shard。如果没有额外指定Distribution Key时,那么会默认将PK设置为Distribution Key ● 如果表没有设置PK时,Distribution Key没有限制,可以为空(不指定任何列)。如果为空,即随机shuffle,数据随机分布到不同shard上。从1.3.28版本开始,Distribution Key禁止为空 ● 如果Distribution Key的列的值中有null时,当作“”(空串看待)。 |
Clustering Key | 是 | 文件内聚簇索引,数据在文件内按该索引排序。因此对于一些范围查询,可以直接通过聚簇索引的数据有序属性进行过滤。 | ● Clustering Key主要适用于点查询、范围查询的场景,对于filter操作有比较好的性能提升。可以同时设置Clustering Key和Bitmap column以达到最佳的点查性能。 ● Clustering Key具备左匹配原则,因此一般不建议超过2个列,否则适用场景减少。同时Clustering Key是用于排序,所以Clustering Key里的列组合是有先后关系的。即排在前面的列的排序优先级高于后面的列。 ● Clustering Key默认为asc,建表时不支持设置为desc。 ● 对于行存表,Clustering Key默认为主键 (0.9之前版本默认不设置)。如果设置为和主键不同的Clustering Key,那么Hologres会为这张表生成两个排序(primary key排序和clustering_key排序),造成数据冗余。 | select sum(a) from tb1 where a > 100 and a < 200; select sum(a) from tb1 where a = 100 ; | ● 如果需要修改Clustering Key,则需要重建建表导入数据。 ● Clustering Key必须为not nullable的列或者列组合。1.3.20-1.3.27版本支持为空,从1.3.28版本开始,不支持Clustering Key为空,为空的Clustering Key可能会影响数据正确性,如果业务有强需求设置Clustering Key为null,可以在SQL前加如下参数:set hg_experimental_enable_nullable_clustering_key = true ● 不支持decimal/numeric/float/double/array/json/jsonb/timestamp及其他复杂数据类型。 ● Clustering Key 指定列时,可在列名后添加 :asc 来构建索引时的排序方式。排序方式默认为asc,即升序。暂不支持desc降序,若是设置了desc降序,无法命中Clustering Key,导致查询性能不佳。 ● 对于列存表,Clustering Key默认为空。需要根据业务场景显示指定 ● 在Hologres中,每个表只能设置一组Clustering Key。即建表的时候只能call一次,不能call多次 |
Segment Key (event_time_column) | 是 | 文件索引,数据以Append Only方式写入文件,随后文件间按该索引键合并小文件,Segment Key标识了文件的边界范围,用户可通过Segment Key快速索引到某一文件。Segment Key是为时间戳、日期等有序,范围类数据场景设计,需要要求Segment Key与数据的写入时间有强相关性。 | ● Segment Key适用于数据为单调递增/单调递减的有序字段,例如时间戳字段,非常适用于日志、流量等和时间强相关的数据,合理设置可极大提升性能。完全无序的event_time_column会导致合并之后每个文件缺乏区分度,达不到任何文件过滤效果! ● 如果表不存在明显的单调递增/单调递减的字段,可以选择额外扩充一列update_time,每次UPSERT时将当前时间写入该新增字段。 ● 因为segment key也具备左匹配原则,因此不建议将多个字段设置为segment key,否则使得查询场景受限,达不到加速效果,一般建议选择设置2个或者2个以内。 | select sum(a) from tb1 where ts > '2020-01-01' and a < '2020-03-02'; | ● event_time_column必须为not nullable的列或者列组合,不支持float/double/array/json及其他复杂数据类型。1.3.20-1.3.27版本支持为nullable,从1.3.28版本开始,不支持segment key为nullable,为nullable的segment key可能会影响数据正确性,如果业务有强需求设置segment key为null,可以在SQL前加如下参数:set hg_experimental_enable_nullable_Segment Key = true ● 修改event_time_column必须重新建表 ● 行存表不能设置event_time_column。 ● 对于列存表,默认为table schema中的第一个not nullable的timestamp/timestamptz的字段为event_time_column,如果不存在这样的字段,则默认为第一个not nullable的date类型的字段 (0.9之前的版本默认为空)。 ● 原名为Segment Key,在 0.9 版本默认改名为event_time_column,Segment Key依旧向下兼容使用。 |
Bitmap Columns | 否 | 文件内位图索引,数据在文件内按该索引列建立位图,对于等值查询,Hologres可以按值对每一行的数据做编码,通过位操作可以快速索引到对应行,时间复杂读为O(1) | ● 适合将等值查询的列设置为Bitmap,能够快速定位到符合条件的数据所在的行号,但需要注意的是Bitmap会占用较多内存,不建议所有列都设置为bitmap,尤其是大宽表启用时要谨慎。 ● 不建议将数值类的字段设置成bitmap,会额外将数值再转化为二进制存储,带来额外开销。 | select * from tb1 where a ='aaabbbcccddd'; | ● 只有列存表和行列共存表支持设置bitmap,行存表不能设置。 ● bitmap指定的列可以为空。 ● 当前版本默认所有text列都会被隐式地设置到bitmap中。 ● 可以在事务之外单独使用,表示修改bitmap_columns列,修改后不能立即生效,在后台异步执行。 |
Dictionary Encoding Columns | 否 | 通过压缩存储的技术将原始数据编码为数值类型存储,同时也会维护对应的编码表结构,在数据读取时,会根据编码表进行数据解码操作,因此在对字符串比较的场景中,尤其是基数小的列,有加速作用,常用于group by、filter等过滤查询场景中。 | ● 建议将有字符串比较的列设置为dictionary_encoding_columns,并且列的基数较低,即数据重复度较高 ● 不建议将所有的列都设置为dictionary_encoding_columns,会带来额外的编码、解码开销。 ● **可以在建表之后单独使用,表示修改dictionary_encoding_columns列,修改之后非立即生效,字典编码构建和删除在后台异步执行。**详情请参见ALTER TABLE。 | select * from tb1 where a='aaabbbcccddd'; select a,sum(b) from agg_tbl group by a; | ● dictionary encoding只能用于列存表或者行列共存表。 ● dictionary_encoding_columns指定的列可以为null。 ● 取值较少的列适合设置dictionary_encoding_columns,可以压缩存储。 ● V0.8及更早版本中默认所有text列都会被隐式地设置到dictionary_encoding_columns中。V0.9及之后的版本会根据数据特征自动选择是否创建字典编码。 |
如何查看索引是否被使用
建表语句如下:
在SQL前加explain运行后,查看执行计划。在Index Scan中查看是否使用了相关索引。
索引相关错误排查&错误原因
1、插入数据报错
原因:
- Primary Key 、Segment Key、Clustering Key不允许数据为空
2、建表失败
原因:
1.行存表不能设置Bitmap Columns,只有列存表和行列共存表支持设置Bitmap Columns2.Primary Key、Distribution Key、Segment Key、Clustering Key不支持复杂数据类型3.若有分区和主键,分区必须为主键的一部分4.行存表必须设置主键,行列共存表必须设置主键,列存表不要求有主键5.行存表不能设置event_time_column6.一个表只能建一个Clustering Key
3、修改表失败
原因:
- 不支持修改Primary Key、Distribution Key、Segment Key、Clustering Key,如需修改主键请重新建表
4、查询未使用到索引
原因:
1.多字段索引的配置
Key(a,b)
where b=1 时,索引无效
where a=1 和 where a=1 and b=1 ,索引有效
底层排序逻辑:先排序a,a相同的各行数据,再按b排序2.Distribution Key的多个字段之前不允许有空格3.Clustering Key只支持asc升序4.Bitmap Columns、Dictionary Encoding Columns修改后异步执行,不能马上生效
5、使用索引后查询速度未改善
原因:
1.distribution key的key分布不均匀,因为数据倾斜导致负载倾斜2.设置为Dictionary Encoding Columns的字段基数较高,也就是说数据重复度低,分散,有额外的解码开销。
总结
本文详细讲解了Hologres的配置步骤,详细对比了不同索引的原理、使用场景、使用限制、使用建议,并给出了索引配置后的排查方法与错误总结,较为完整地阐述索引相关的技术细节。
对您有帮助吗?
对您有帮助吗?