设置列索引的排序键
本文介绍了列存索引数据的排序流程、使用方法以及构建和查询有序列存索引数据的时间对比等内容。
简介
列存索引数据是按照行组进行组织,默认包含64K行。每个行组中不同的列会各自打包形成列数据块,列数据块按照行存原始数据的主键次序并行构建,更新数据则按照追加次序写入,总体上是无序的。
列存索引支持粗糙索引,每一个列数据块的元数据包含全部数据的最小值和最大值等信息。查询数据时,正常情况下需要遍历指定列的所有列数据块。开启Pruner后,会根据查询条件与元数据信息将所有列数据块分为相关、可能相关和不相关三大类。读取数据时只考虑相关和可能相关的列数据块。列数据块有不同次序的组织方式,进而会产生不同组合的列数据块集合,Pruner也会有不同的过滤效果,因此,用户可以根据查询条件来修改列数据块的排列顺序,以提高查询性能。
如上图所示,当执行以下SQL语句时,针对无序列数据块集合,需要加载所有列数据块并进行处理。而有序数据块集合则可以通过每个列数据块内存中元数据的最大值和最小值等信息过滤掉第一个列数据块,只需要针对第二个列数据块进行处理即可。
SELECT * FROM t WHERE c >= 8;
前提条件
开启新增列存索引时数据排序功能,企业版集群版本需满足以下条件之一:
PolarDB MySQL版8.0.1版本且修订版本为8.0.1.1.32及以上。
PolarDB MySQL版8.0.2版本且修订版本为8.0.2.2.12及以上。
开启增量数据排序功能,企业版集群需为PolarDB MySQL版8.0.1版本且修订版本为8.0.1.1.36及以上。
您可以通过查询版本号来确认集群版本。
注意事项
新建列存索引时数据排序只针对现存数据,即不会持续处理不断更新的数据。建议您根据业务特点来定时构建数据或开启增量数据排序功能。
暂不支持在主节点开启列存索引数据排序功能。
不支持将BLOB、JSON和GEOMETRY类型的数据作为排序键。
增量数据排序仅支持对有符号整数类型的排序键进行增量数据排序。当排序键包含多列时,只按照第一列维护增量数据的有序性。
增量数据排序会占用一定的资源。因此,当集群的写入负载较高时,为了让出更多的资源供前台写入数据,增量数据排序的速度会变慢。
排序流程
新建列存索引时数据排序流程
列存索引数据排序总体上实现与DDL过程中二级索引的排序算法类似,支持单线程与多线程排序。单线程使用标准二路归并排序,多线程使用败者树多路外排且支持抽样排序法策略。总体流程如下:
按照主键索引遍历并将读取到的完整数据保存至数据文件,然后将排序列添加到排序缓存区,其中每个线程使用不同的数据文件,累积达到一定数据后再写入;
不断遍历并插入到排序缓存区,当排序缓存区满时,在内存中根据排序键组合进行排序并保存到合并文件中;
遍历完成后,对合并文件按段两两排序,并将排序后的数据保存在临时文件中,随后将合并文件与临时文件进行切换;
重复执行步骤3,直到合并文件有序排列,然后读取合并文件中的每一行记录,根据偏移值读取数据文件中对应的记录并追加到列存索引中。
增量数据排序流程
增量数据的排序流程是渐进式的,不能保证数据完全有序。总体流程如下:
将所有的数据块进行两两分组,挑选出多个数据范围重合度较高的数据块组。
将每个数据块组进行归并排序,生成两个有序的数据块。
重复执行步骤2,直到所有的数据块有序排列。
参数说明
您需要在数据库中设置下表中参数的值,来开启或关闭列存索引排序功能,以及根据实际业务需求设置线程数量等信息。
参数 | 说明 |
imci_enable_pack_order_key | 新建列存索引时数据排序功能控制开关。取值如下:
|
imci_enable_sort_compaction | 增量数据排序功能控制开关。取值范围如下:
|
imci_parallel_build_threads_per_table | 构建列存索引数据的单张表的线程数量。 取值范围:1~128。默认值为4。 |
imci_parallel_build_merge_ways | 并行构建有序列存数据时归并排序的路数。 取值范围:2~16。默认值为2。 |
imci_parallel_build_use_parallel_load | 并行构建有序列存数据时是否并发读取数据文件。取值如下:
|
使用说明
您可以按照以下步骤来使用列存索引数据排序功能:
开启列存索引排序功能。
开启新建列存索引时数据排序功能。
将参数
imci_enable_pack_order_key
的值设置为ON,来开启新建列存索引时数据排序功能。开启增量数据排序功能。
将参数
imci_enable_sort_compaction
的值设置为ON,来开启增量数据排序功能。
在以下SQL语句的
comment
中添加order_key
属性来构建有序列存索引数据。ALTER TABLE table_name COMMENT 'columnar=1 order_key=column_name[,column_name]';
参数说明
参数
说明
table_name
表名。
column_name
列名。您可以配置多个列名,多个列名之间使用英文逗号(,)分隔。
说明当
order_key
的第一列的值为有符号整型时,在列存索引构建结束后,增量数据会在后台不断地维护有序性。当只需要增量数据排序而无需全量排序时,您可以将参数
imci_enable_pack_order_key
的值设置为OFF,将参数imci_enable_sort_compaction
的值设置为ON。此时,当重建表的列索引时,不会对已有的数据进行排序,但增量数据会维护有序性。
您可以在
INFORMATION_SCHEMA.IMCI_ASYNC_DDL_STATS
表中查看列存索引数据的构建进度。INFORMATION_SCHEMA.IMCI_ASYNC_DDL_STATS
表的详细信息请参见查看列存索引构建的执行进度。
SELECT * FROM INFORMATION_SCHEMA.IMCI_ASYNC_DDL_STATS;
您可以在INFORMATION_SCHEMA.IMCI_INDEX_STATS
表的MAX_ORDER_KEY_OVERLAP
列查看数据块组的数据范围重合度。
SELECT * FROM INFORMATION_SCHEMA.IMCI_INDEX_STATS;
列存索引数据排序与DDL排序的区别
列存索引数据排序的本质是按照指定键组合进行排序,类似于其他普通二级索引DDL排序过程,但两者也有不同之处,具体区别如下:
列存索引排序不使用索引列作为排序键,而是可以指定任意组合的排序键。
列存索引排序后,需要读取完整的数据。而二级索引DDL仅需要保存索引部分的数据。如VARCHAR字段只保存前缀部分作为索引数据。
有序列存索引数据构建和查询时间对比
以TPCH 100 GB为例,测试构建和查询有序列存索引数据的时间。
测试构建有序列存索引数据的时间。
以
lineitem
表为例,来构建有序列存索引数据,且并行线程数量为16。示例如下:ALTER TABLE lineitem COMMENT='columnar=1 order_key=l_receiptdate,l_shipmode';
构建时间如下:
无序数据集
有序数据集
有序数据集(将parallel_build_use_parallel_load参数值设置为OFF)
6分钟
35分钟
4小时
测试有序列存索引数据的查询时间。
以TCPH的Q12为例,在LRU缓存与执行器内存均为10 GB的配置下,执行如下查询语句:
SELECT l_shipmode, SUM(CASE WHEN o_orderpriority = '1-URGENT' OR o_orderpriority = '2-HIGH' THEN 1 ELSE 0 END) AS high_line_count, SUM(CASE WHEN o_orderpriority <> '1-URGENT' AND o_orderpriority <> '2-HIGH' THEN 1 ELSE 0 END) AS low_line_count FROM orders, lineitem WHERE o_orderkey = l_orderkey AND l_shipmode in ('MAIL', 'SHIP') AND l_commitdate < l_receiptdate AND l_shipdate < l_commitdate AND l_receiptdate >= date '1994-01-01' AND l_receiptdate < date '1994-01-01' + interval '1' year GROUP BY l_shipmode ORDER BY l_shipmode;
查询时间如下:
无序数据集
有序数据集
有序数据集(将parallel_build_use_parallel_load参数值设置为OFF)
7.47s
1.25s
1.26s