PolarDB PostgreSQL版支持共享Detoast(Shared Detoast)功能,能够避免对同一大字段的重复Detoast操作,提升查询执行效率。
功能简介
PostgreSQL使用TOAST(The Oversized-Attribute Storage Technique,超大字段存储技术)机制存储超大字段(如大型JSONB、长文本、大二进制数据等)。当查询需要访问这些字段的实际内容时,需要执行Detoast操作,将分段存储(且可能压缩过)的数据重新组装、解压为完整数据。
原生PostgreSQL的Detoast是惰性执行的:每个访问该字段的表达式都会独立执行一次Detoast,彼此之间无法共享结果。例如:
SELECT big_jsonb->'a', big_jsonb->'b', big_jsonb->'c',
big_jsonb->'d', big_jsonb->'e'
FROM t;上述查询会对同一行的big_jsonb列重复执行5次Detoast,当字段较大时会带来显著的CPU与内存分配开销。
PolarDB PostgreSQL版提供共享Detoast功能:同一行数据在执行器中第一次Detoast后,结果会被缓存并在该行的后续表达式求值中直接复用,避免重复Detoast,以少量内存开销换取显著的性能提升。该功能对JIT执行同样生效。
适用范围
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(内核小版本2.0.14.10.19.0及以上)
适用场景
以下场景可以从共享Detoast功能中获益:
同一大字段被多个表达式访问:如对同一JSONB列提取多个键(
WHERE big->>'c3' = '1' AND big->>'c4' = '2'中big只需Detoast一次)、对同一长文本列执行多个函数运算等。输出列表中对同一JSON列输出多个字段:如
SELECT big->'a', big->'b', big->'c' FROM t,同一行的big列只需Detoast一次,多个取值表达式直接复用。大字段同时出现在过滤条件和输出列表中:如
WHERE big->>'type' = 'x'且SELECT big->'payload'。连接(Join)条件与输出同时引用大字段:支持
Nested Loop、Hash Join、Merge Join等连接节点。
访问次数越多、字段越大,收益越明显。
注意事项与限制
共享Detoast功能存在以下注意事项与限制:
内存开销:共享Detoast功能以内存换时间。缓存Detoast结果会增加单行处理时的内存占用(约为相关字段解压后的大小),但缓存随行处理结束即释放,通常不会造成明显的内存压力。
部分计划节点不启用:当大字段位于
Sort、Hash(Hash Join内表)、Materialize、Memoize、WindowAgg、增量排序等需要物化元组的节点下游时,为避免物化后的元组过大(导致work_mem更快耗尽、产生额外的临时文件I/O),优化器会自动对相关列禁用共享Detoast功能。这是自动行为,无需您手动干预。仅对被表达式访问的列生效:
只有在表达式中被直接运算的TOAST列(如
big->'key'、length(big_text))才会提前Detoast。仅作为结果原样输出的列(如
SELECT big FROM t)不受影响,仍保持原生惰性行为。
对不涉及大字段的负载有轻微开销:共享Detoast功能会在生成执行计划时额外遍历计划树,并为元组槽维护独立的内存上下文。在完全不涉及TOAST大字段的高频短查询场景(如sysbench OLTP类负载)下,实测有小于3%的性能损耗。若业务以此类负载为主且追求极致性能,可将
polar_enable_shared_detoast_datum参数设为OFF,关闭后性能与不含该功能的版本持平。结果正确性不受影响:共享Detoast功能仅改变Detoast的执行时机与复用方式,不改变任何查询语义与结果。
使用方法
共享Detoast功能由参数polar_enable_shared_detoast_datum控制,在符合版本条件的集群上默认开启,无需任何配置即可使用。
控制台修改polar_enable_shared_detoast_datum参数的能力将在新版本中开放。如果当前控制台中看不到该参数,可以联系技术支持。
参数名称 | 描述 |
| 用于控制共享Detoast功能的开关,bool类型,取值如下:
|
功能开启后,优化器会在生成执行计划时自动识别可受益的查询并应用优化,对不适用的场景自动跳过,无需您手动干预。polar_enable_shared_detoast_datum参数在优化器生成执行计划时生效,修改后对新执行的查询(含重新生成计划的预编译语句)生效。
polar_enable_shared_detoast_datum参数支持会话级修改,可在会话内临时关闭或开启,用于对比验证优化效果:
会话级设置仅对当前连接有效,连接断开后恢复默认值。
-- 当前会话内关闭
SET polar_enable_shared_detoast_datum = off;
-- 当前会话内开启
SET polar_enable_shared_detoast_datum = on;使用示例
构造包含大JSONB字段的测试表,并对同一JSONB列多次取值。同一行的big列只需Detoast一次:
-- 构造包含大 JSONB 字段的测试表 CREATE TABLE t_big (id int, big jsonb); INSERT INTO t_big SELECT i, (SELECT jsonb_object_agg(k, repeat('x', 1000)) FROM generate_series(1, 100) k) FROM generate_series(1, 10000) i; -- 对同一 JSONB 列多次取值 EXPLAIN ANALYZE SELECT big->'1', big->'2', big->'3', big->'5', big->'10' FROM t_big;可通过对比开启/关闭参数时
EXPLAIN ANALYZE的执行时间,验证优化效果:SET polar_enable_shared_detoast_datum = off; EXPLAIN ANALYZE SELECT big->'1', big->'2', big->'3', big->'5', big->'10' FROM t_big; SET polar_enable_shared_detoast_datum = on; EXPLAIN ANALYZE SELECT big->'1', big->'2', big->'3', big->'5', big->'10' FROM t_big;