更新时间:2026-07-28 GMT+08:00
分享

hashbucket剪枝

在使用hashbucket表的时候,当select语句中谓词列和hashbucket表分布列相同时,会对hashbucket表进行剪枝操作,大幅缩减访问的bucket的数量。示例如下:
--准备环境。
gaussdb=# SET enable_fast_query_shipping=off;
gaussdb=# CREATE TABLE t1 (a int, b int, c int) WITH (hashbucket=on, storage_type=astore);
gaussdb=# INSERT INTO t1 VALUES(generate_series(1, 10), generate_series(1, 10));
gaussdb=# ANALYZE t1;
--展示执行计划。
gaussdb=# EXPLAIN (costs false,verbose on) SELECT count(*) FROM t1 WHERE a = 1;
                      QUERY PLAN
-------------------------------------------------------
 Aggregate
   Output: pg_catalog.count(*)
   ->  Streaming (type: GATHER)
         Output: (count(*))
         Node/s: datanode1
         ->  Aggregate
               Output: count(*)
               ->  Seq Scan on public.t1
                     Output: a, b, c
                     Distribute Key: a
                     Filter: (t1.a = 1)
                     Selected Buckets 1 of 1024 : 325
(12 rows)

可以看到计划中显示选择了325这个编号的bucket,则在实际执行的时候会直接读取这个bucket的数据,减少无意义的读取。

关于hashbucket的计划需要打开explain verbose才能显示。

hashbucket参数化路径剪枝

当选择参数化路径计划且hashbucket表作为内表时,若参数化的列是hashbucket表的分布列,会进行参数化路径的剪枝,动态削减访问bucket的数量。

--准备环境。
gaussdb=# SET enable_fast_query_shipping=off;
gaussdb=# CREATE TABLE t2 (a int, b int, c int) WITH (hashbucket=on, storage_type=astore);
gaussdb=# INSERT INTO t2 VALUES(generate_series(1, 10), generate_series(1, 10));
gaussdb=# CREATE INDEX index_t2 on t2(a, b);
gaussdb=# ANALYZE t2;
--展示执行计划。
gaussdb=# EXPLAIN (costs false,verbose on) SELECT /*+ nestloop_index(t2, index_t2)*/* FROM t1 JOIN t2 ON t1.b = t2.a;
                           QUERY PLAN
-----------------------------------------------------------------
 Streaming (type: GATHER)
   Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
   Node/s: All datanodes
   ->  Nested Loop
         Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
         ->  Streaming(type: REDISTRIBUTE)
               Output: t1.a, t1.b, t1.c
               Distribute Key: t1.b
               Spawn on: All datanodes
               Consumer Nodes: All datanodes
               ->  Seq Scan on public.t1
                     Output: t1.a, t1.b, t1.c
                     Distribute Key: t1.a
                     Selected Buckets 1024 of 1024 : all
         ->  Index Scan using index_t2 on public.t2
               Output: t2.a, t2.b, t2.c
               Distribute Key: t2.a
               Index Cond: (t2.a = t1.b)
               Selected Buckets 1024 of 1024 : all (ppi-pruning)
(19 rows)

可以看到在Selected Buckets 这段有ppi-pruning标识,标识这个计划会执行参数化路径剪枝。

若需要知道具体的剪枝操作,可以在DN上执行explain analyze语句。
--直连DN。
gaussdb=# EXPLAIN (costs false,verbose on,analyze on) SELECT /*+ nestloop_index(t2, index_t2)*/* FROM t1 JOIN t2 on t1.b = t2.a;
                                       QUERY PLAN
----------------------------------------------------------------------------------------
 Nested Loop (actual time=4.743..10.928 rows=6 loops=1)
   Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
   ->  Seq Scan on public.t1 (actual time=4.607..10.471 rows=6 loops=1)
         Output: t1.a, t1.b, t1.c
         Selected Buckets 1024 of 1024 : all
   ->  Index Scan using index_t2 on public.t2 (actual time=0.124..0.132 rows=6 loops=6)
         Output: t2.a, t2.b, t2.c
         Index Cond: (t2.a = t1.b)
         Selected Buckets 1024 of 1024 : all (ppi-pruning) actual scan bucket num:6
 Total runtime: 23.424 ms
(10 rows)

可以看到计划中有actual scan bucket num:6 这样一个字段,表示总共访问了6个bucket。

特性约束

  • 支持bucket类型:hashbucket。
  • 支持算子类型:indexscan、indexonlyscan、bitmapscan。
  • 支持表达式类型:比较表达式(<,<=,=,>=,>)、逻辑表达式(and)。
  • 不支持子查询表达式,不支持stable和volatile函数,不支持跨QueryBlock参数化路径,不支持BitmapOr、BitmapAnd算子。
  • 只支持LBI(local bucket index) 不支持 cross bucket index。
  • 只支持单分布列。
  • 外连接驱动hashbucket表时,只支持=条件。

相关文档