云原生数据仓库AnalyticDB PostgreSQL版Beam存储引擎提供的字典编码功能,可以将低基数的字符串类型数据压缩为整型数据,提升存储效率,加速过滤、聚合等类型查询的性能。
注意事项
仅存储弹性模式v7.0.x版本支持Beam字典编码功能。
Beam字典编码功能在存储弹性模式v7.0.6.2版本中结束公测正式上线,该版本修复了公测中的问题,建议您尽快升级到v7.0.6.2及以上版本。
字典编码存储压缩
使用数据压缩功能可以节约表的存储空间,并减少查询时从磁盘读取的数据量大小,进而减少I/O以提升查询性能。针对不同类型的数据,合理地选择压缩算法可以更好的帮助您提升数据库的性能。
AnalyticDB PostgreSQL版字典编码压缩仅支持字符串类型。字典编码既支持列级别压缩,也支持表级别压缩。
列级别使用字典编码压缩时,仅对指定列进行压缩,且需要保证列的数据类型为字符串类型。
表级别使用字典编码压缩时,满足低基数要求的列会被压缩。针对非字符串类型的列,建表时不进行压缩。
本文以TPC-H的nation
表为例,在使用Beam存储表的情况下,通过compresstype='gdict'
指定表级别使用字典编码压缩,n_name
和n_comment
两列都会用字典编码进行压缩,示例如下。
CREATE TABLE NATION (
n_nationkey integer NOT NULL,
n_name character(25) NOT NULL,
n_regionkey integer NOT NULL,
n_comment character varying(152)
)
USING beam WITH (compresstype = 'gdict')
DISTRIBUTED by (n_nationkey);
您也可以只针对指定列n_name
使用字典编码,示例如下。
CREATE TABLE NATION (
n_nationkey integer NOT NULL,
n_name character(25) NOT NULL ENCODING (compresstype='gdict'),
n_regionkey integer NOT NULL,
n_comment character varying(152)
)
USING beam WITH (compresstype = 'lz4', compresslevel = 9)
DISTRIBUTE by (n_nationkey);
在对n_name
列使用压缩编码后,存储的数据大小从25 Byte(character(25)
类型对字符串末尾补齐空格)压缩至2 Byte,显著减少了数据使用的存储空间。
n_name 字符串值 | 大小(Byte) | 字典值 | 压缩编码大小(Byte) |
ALGERIA | 25 | 0 | 2 |
ARGENTINA | 25 | 1 | 2 |
BRAZIL | 25 | 2 | 2 |
CANADA | 25 | 3 | 2 |
CHINA | 25 | 4 | 2 |
EGYPT | 25 | 5 | 2 |
ETHIOPIA | 25 | 6 | 2 |
FRANCE | 25 | 7 | 2 |
总计 | 200 | / | 16 |
字典编码执行加速
使用字典编码存储后,可以进一步在执行层使用字典压缩后的值加速查询计算,在低基数字符串过滤、聚合、排序等场景中获得执行加速性能提升,根据SQL模式的不同,可以在执行中获得10%至200%的性能提升。
字典编码执行加速功能由参数adbpg_enable_encode_optimize
控制,默认配置为OFF(关闭)。对于适合使用字典编码执行加速的SQL,优化器会自动生成对应的优化计划。例如,对于如下SQL:
SELECT
n_name,
max(n_regionkey)
FROM
nation
WHERE
n_name > 'ALGERIA'
AND n_name < 'FRANCE'
GROUP BY
n_name;
使用EXPLAIN查看执行计划,可以看到计划中使用的编码方法,并引入了Decode算子进行计算过程中的解码。
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3) (cost=76.72..78.27 rows=81 width=36)
-> GroupAggregate (cost=76.72..77.19 rows=27 width=36)
Group Key: n_name
-> Sort (cost=76.72..76.79 rows=28 width=36)
Sort Key: n_name
-> Redistribute Motion 3:3 (slice2; segments: 3) (cost=0.00..76.05 rows=28 width=36)
Hash Key: n_name
-> Decode (cost=0.00..75.50 rows=28 width=36)
Params: dictKeyIdx[1], dictID[0]
-> Seq Scan on nation (cost=0.00..75.50 rows=28 width=36)
Filter: ((ordered_encode(n_name) > ('ALGERIA'::text)::integer with dict ID 0) AND (ordered_encode(n_name) < ('FRANCE'::text)::integer with dict ID 0))
Optimizer: Postgres query optimizer
(12 rows)
相比较字符串类型的数据运算,字典编码后的整型数据运算可以有效地提升查询性能;同时优化器会在执行计划中合适的位置插入Decode算子,对存储层读取到的字典编码数据进行解码,保证执行的准确性。
使用自动压缩编码优化
Beam存储引擎支持自适应的压缩算法。如果您不确定是否需要使用字典编码压缩,可以在表级别指定compresstype = 'auto'
,存储引擎会自动选择合适的编码压缩算法。
CREATE TABLE NATION (
n_nationkey integer NOT NULL,
n_name character(25) NOT NULL,
n_regionkey integer NOT NULL,
n_comment character varying(152)
)
USING beam WITH (compresstype = 'auto')
DISTRIBUTE by (n_nationkey);
对nation
表使用自动压缩编码后,各列的编码如下所示:
列 | 数据类型 | 编码方法 | 说明 |
n_nationkey | integer | LZ4编码或int编码 | 整型数据,默认使用LZ4编码或int编码。 |
n_name | character(25) | 字典编码 |
|
n_regionkey | integer | LZ4编码或int编码 | 整型数据,默认使用LZ4编码或int编码。 |
n_comment | character varying(152) | 字典编码 |
|
字典编码支持Delta
Beam存储引擎包含两部分:
用以应对实时写入的行存格式的Delta。
用以应对批量写入和大量扫描场景的基于PAX结构的列存格式的Base。
v7.0.2.3及以上版本的实例支持行列混存Base。
v7.0.4.0及以上版本的实例字典编码适配行存格式Delta,提高了字典编码的易用性。
例如,执行如下SQL,使用EXPLAIN查看执行计划,可以看到计划中使用Decode算子进行计算过程中的解码,可以提高数据处理效率及数据安全性,进而提高字典编码的易用性。
CREATE TABLE test_auto(a int, b text)
using beam with(compresstype=auto,compresslevel=5);
INSERT INTO test_auto values (1,'adbpg1'),(2,'adbpg2'), (3, 'adbpg3'),(10,'adbpg10');
SET adbpg_enable_encode_optimize to ON;
explain SELECT * FROM test_auto WHERE b='adbpg1';
-----------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2.04 rows=1 width=36)
-> Decode (cost=0.00..2.02 rows=1 width=36)
Params: dictKeyIdx[2], dictID[0]
-> Seq Scan on test_auto (cost=0.00..2.02 rows=1 width=36)
Filter: (encode(b) = ('adbpg1'::text)::integer with dict ID 0)
Optimizer: Postgres-based planner