PG 向量化引擎--2

来源:这里教程网 时间:2026-03-14 20:28:38 作者:

PG 向量化引擎 --2 向量化引擎是 OLAP 数据库提升性能的有效技术。翻到 PostgreSQL 邮件列表有对向量化引擎的讨论。这里继续进行整理,以作分析。

关于设计中的几个问题

1 、在 vtype 中使用原生数组而不是 Datum 数组会更有效吗?我认为针对 float4 int32 类型的操作,它将允许编译器产生更加有效的代码 是的,我也在考虑扫描列存时,将列 batch 加载到连续的内存区域中。对于 Int32 ,此区域大小时 4*BATCHSIZE ,而对于 Int16 ,大小时 2*BATCHSIZE 。所以使用原生数据可以只做一个 memcpy 来填充 vtype batch 2 、为什么 VectorTupleSlot 中包含元组的数据( batch )而不是向量( vtype 的数组)? 首先, VectorTupleSlot tts_values 域存储 vtype 的数组,这样做减少了代码的更改量,摈弃可以重用像 ExecProject 类似的函数。当然,我们也可以使用单独的字段来存储 vtypes 其次, VectorTupleSlot 还包含堆元组数据。这属于堆元组的变形。事实上,一个 batch 中包含的元组可能跨多个页。因此我们需要 pin 住相关页的数组,而不仅仅是一个页 3 、为什么必须实现子集的 plan_tree_mutator 而不是使用 expression_tree_mutator? 我也想要替换 Plan 节点,例如 Agg->CustomScan( 使用 VectorAgg 实现 ) expression_tree_mutator 不能够用于变异 plan node ,如 Agg ,对吗? 4 、据我了解,您现在总是尝试用自己定义的向量化 scan 来替代 SeqScan 。但只有当此扫描或聚合执行了 quals 才有意义。其他情况下, batch+unbatch 只会增加额外的开销,不是吗? 可能 heap 格式和 select i from t 没有 qual projection aggregation 的查询才会有额外的开销。但是对于列存, VectorScan 可以直接读 batch ,没有额外的 batch 代价。列存是 OLAP 查询更好的选择。我们是否可以得出结论,对于 OLAP 查询使用向量化引擎,对于 OLTP 查询使用行引擎会更好。 5 、对于不能向量化的查询捕获并抛出异常不是处理此类情况最安全和最有效的方法。在 plan_tree_mutator 中返回错误代码,并将此错误传播到上层可能会更好吗? 是的,至于效率,另一种方法是仅对某些 plan 节点进行向量化,而其他节点不向量化,通过在他们之间添加 batch/unbatch 节点来实现(这是你说的“在上层传播此错误”?)。正如您所提到的,这可能会带来额外的开销,还有其他好的方法吗?您说的最不安全是什么意思? PG catch 接收 ERROR ,反馈给原始非向量化 plan --hackers 中对 catching 和忽略 exception 进行了多次讨论,不幸的是 PG PG_TRY/PG_CATCH 机制不是高级语言 C++ java 等机制的变种。它不会执行堆栈 unwind 。如果在抛出错误之前获取了一些资源( files locks memory 等),那么这些资源不会回收。仅回滚事务才能释放所有资源。实际上它发生在正常错误处理情况下。但如果捕获并忽略异常,视图继续执行,那么可能会导致更多问题。 可能在您情况下,这个不是问题,因为您确定错误发生在哪里,他是由 plan_tree_mutator 抛出的,并且看起来这个函数没有获得任何资源。但是在任何情况下 setjmp 开销都远高于对返回码的显式检查。因此,检查返回码实际上不会增加一些明显的开销,除了通过添加额外的检查使得代码复杂化。但是可以通过宏例如 MUTATE 来隐藏这些复杂度。 6 、你测试过不同 batch 大小吗?我在 VOPS 中做了类似测试,发现大于 128 的大小并没有带来显著的性能提升。你当前使用 batch 大小是 1024 ,它明显大于一页上元组数量。 好的,将对此进行一些实验 7 、如何将向量化扫描和并行结合起来( 9.6 已支持) 目前还没实现。但这个想法与非并行的想法相同。复制当前并行扫描并实现向量化 Gather ,保持接口都是 VectorTupleTableSlot 。我们基本思路是复用当前 PG 执行逻辑大部分代码,然后进行向量化,并逐步进行性能调优。 -- 并行扫描时在并行 worker 之间分散页。为填充 VectorTupleSlot ,可能需要不止一页(除非你决定仅在单页中获取元组)。因此应该以某种方式考虑并行查询的具体请。还有用于并行查询的特殊节点,所以如果我们想为向量化操作提供并行执行,我们还需要用自定义节点替换这个节点。

做的一些性能测试

Q1 的结果:

max_parallel_workers_per_gather

PG9_6, enable_vectorize_engine=off

PG9_6, enable_vectorize_engine=on

master (jit=on)

0

36

20

10

4

10

--

5

9.6 相比, PG13 OLAP 查询中提供了显著优势。当然并不意味着新版本的 PG 不需要向量化执行器。无论如何,我认为向量化执行器至于与列存结合才有意义。

Konstantin Knizhnik 的测试

vectorize_engine 移植到 master 。花费的时间比预期要长: executor 代码中很多东西都发生了改变:

par.warkers

PG9_6 矢量化=关闭

PG9_6 矢量化=开启

矢量化=关闭 jit=打开

矢量化=关闭 jit=关闭

矢量化=on jit=ofn

矢量化=on jit=off

0

36

20

16

25.5

15

17.5

4

10

-

5

7

-

-

因此,它证明了 JIT 提供与向量化执行器计划相同的加速理论(这这都消除了解释开销,但方式不同)。我仍然不确定我们是否需要向量化执行器:因为与当前的 JIT 版本相比,标准 heap 几乎没有任何改进。但无论如何,我们将使用列存 zedstore cstore 对其进行测试。 列存的比较

par.workers

PG9_6 vectorize=off

PG9_6 vectorize=on

master vectorize=off jit=on

master vectorize=off jit=off

master vectorize=on jit=on

master vectorize=on jit=off

zedstore vectorize=off jit=on

zedstore vectorize=off jit=off

zedstore vectorize=on jit=on

zedstore vectorize=on jit=off

0

36

20

16

25.5

15

17.5

18

26

14

16

4

10

-

5

7

-

-

5

7

-

-

差距很小。

原文

https://postgrespro.com/list/id/CAB0yrenYmbYsioz167OrcO_8wVsvb=MA381-McLNcjEb1EJQYg@mail.gmail.com

相关推荐