实验五 静态剪枝

概念介绍

分区剪枝 是指数据库在扫描分区表时,根据查询条件只扫描目标数据所在分区。通过分区剪枝可以大大减少从磁盘检索的数据量,提高查询性能。分区剪枝分为静态剪枝和动态剪枝。

分区剪枝是被动触发的,一般情况下,当查询 SQL 的条件带有分区列且能确定扫描分区时,数据库会进行分区剪枝。

如果分区列条件使用静态谓词,数据库进行静态剪枝;如果分区列条件使用绑定变量,数据库进行动态剪枝。
静态剪枝发生在SQL解析过程中,在 SQL 执行前,数据库就知道了需要扫描的分区。

实验介绍

本实验以 TPCC 业务表为例,通过分析分区表静态剪枝的基本行为、触发条件、剪枝前后行为对比,了解数据库是如何通过分区静态剪枝提升分区表的查询性能。

实验目的

了解静态剪枝的基本原理及触发条件。

了解如何判断 SQL 是否发生了静态剪枝。

了解如何合理使用静态剪枝提升分区表查询性能。

实验步骤

步骤1在数据库中创建分区表,用于验证静态剪枝功能。

GaussDB 在分布式环境下,支持 RANGE 分区表。

设置参数:
set enable_fast_query_shipping = off;
set enable_stream_operator = on;

该两个参数为会话级,只在本次会话期间生效。

使用以下语句,创建一张RANGE 分区表 bmsql_stock。

sql 复制代码
DROP TABLE IF EXISTS bmsql_stock;
CREATE TABLE bmsql_stock
( s_w_id INTEGER NOT NULL,
s_i_id INTEGER NOT NULL,
s_quantity INTEGER,
s_ytd INTEGER,
s_order_cnt INTEGER,
s_remote_cnt INTEGER,
s_data VARCHAR(50),
s_dist_01 CHAR(24),
s_dist_02 CHAR(24),
s_dist_03 CHAR(24),
s_dist_04 CHAR(24),
s_dist_05 CHAR(24),
s_dist_06 CHAR(24),
s_dist_07 CHAR(24),
s_dist_08 CHAR(24),
s_dist_09 CHAR(24),
s_dist_10 CHAR(24)
)PARTITION BY RANGE(s_w_id)
(
PARTITION stock_p1 VALUES LESS THAN (35),
PARTITION stock_p2 VALUES LESS THAN (70),
PARTITION stock_p3 VALUES LESS THAN (MAXVALUE)
);

步骤2导入数据

sql 复制代码
jiang=# INSERT INTO bmsql_stock SELECT generate_series(1,100),generate_series(1,999);
INSERT 0 99900
jiang=#

步骤3 通过查看打印的计划,判断一级分区是否发生静态剪枝。

剪枝是被动触发的,可以通过查看SQL 的执行计划来判断是否发生了剪枝。若只扫描了部分分区,则表明发生了剪枝行为;若扫描了全部分区,则表明未发生剪枝行为。

在打印执行计划前,执行参数设置:
set max_datanode_for_plan = 1;

该参数是会话级的,只在本次会话期间生效。

a.查看如下 SQL 的执行计划。

sql 复制代码
jiang=# EXPLAIN SELECT * FROM bmsql_stock WHERE s_w_id = '59' AND s_i_id = '23';
 id |                   operation                   | E-rows | E-width | E-costs 
----+-----------------------------------------------+--------+---------+---------
  1 | ->  Streaming (type: GATHER)                  |      1 |    1142 | 2.33
  2 |    ->  Partition Iterator                     |      1 |    1142 | 1.21
  3 |       ->  Partitioned Seq Scan on bmsql_stock |      1 |    1142 | 1.21
(3 rows)

   Predicate Information (identified by plan id)   
---------------------------------------------------
   2 --Partition Iterator
         Iterations: 1
   3 --Partitioned Seq Scan on bmsql_stock
         Filter: ((s_w_id = 59) AND (s_i_id = 23))
         Selected Partitions:  2
(5 rows)

表 bmsql_stock 的分区列为 s_w_id,由于查询 SQL 带有条件 s_w_id = '59',通过静态剪枝,可以只访问指定分区的数据,跳过其他分区的处理。

Iterations 值为 1,表示数据库只访问了单个分区,Selected Partitions 值为 2,表示访问了第 2 个分区。从分区定义可以看出,s_w_id = '59'落在了第 2 个分区 stock_p2,与静态剪枝结果对应。

b.将条件改成s_w_id > '59' AND s_i_id = '23',查看执行计划。

sql 复制代码
jiang=# EXPLAIN SELECT * FROM bmsql_stock WHERE s_w_id > '59' AND s_i_id = '23';
 id |                   operation                   | E-rows | E-width | E-costs 
----+-----------------------------------------------+--------+---------+---------
  1 | ->  Streaming (type: GATHER)                  |     41 |    1142 | 516.11
  2 |    ->  Partition Iterator                     |     41 |    1142 | 500.50
  3 |       ->  Partitioned Seq Scan on bmsql_stock |     41 |    1142 | 500.50
(3 rows)

   Predicate Information (identified by plan id)   
---------------------------------------------------
   2 --Partition Iterator
         Iterations: 2
   3 --Partitioned Seq Scan on bmsql_stock
         Filter: ((s_w_id > 59) AND (s_i_id = 23))
         Selected Partitions:  2..3
(5 rows)

可以看到,数据库基于条件 s_w_id > '59'进行静态剪枝,确定访问了分区 2 和分区 3,对应分区名为 stock_p2 和 stock_p3。

c.将条件改成 s_i_id = '23',查看执行计划。

sql 复制代码
jiang=# EXPLAIN SELECT * FROM bmsql_stock WHERE s_i_id = '23';
 id |                   operation                   | E-rows | E-width | E-costs 
----+-----------------------------------------------+--------+---------+---------
  1 | ->  Streaming (type: GATHER)                  |    100 |    1142 | 654.05
  2 |    ->  Partition Iterator                     |    100 |    1142 | 617.25
  3 |       ->  Partitioned Seq Scan on bmsql_stock |    100 |    1142 | 617.25
(3 rows)

 Predicate Information (identified by plan id) 
-----------------------------------------------
   2 --Partition Iterator
         Iterations: 3
   3 --Partitioned Seq Scan on bmsql_stock
         Filter: (s_i_id = 23)
         Selected Partitions:  1..3
(5 rows)

由于分区键 s_w_id 上不带有任何条件,数据库不会进行分区剪枝,会访问全部的 3 个分区。

步骤4验证静态剪枝的触发条件

分区列使用静态谓词,若符合剪枝条件,可以触发静态剪枝。

对于 RANGE 分区,符合剪枝条件的静态谓词包括范围表达式(>、>=、=、<=、<)、IN 查询,以及由此组合的布尔表达式(AND、OR);对于 LIST 分区和 HASH 分区,范围表达式仅支持等号查询,其他场景与RANGE 分区一致。需要注意的是,当分区列发生类型转换时,无法触发静态剪枝。

a.分区列发生类型转换,无法触发静态剪枝。

sql 复制代码
jiang=# EXPLAIN SELECT * FROM bmsql_stock WHERE s_w_id = 59.1;
 id |                   operation                   | E-rows | E-width | E-costs 
----+-----------------------------------------------+--------+---------+---------
  1 | ->  Streaming (type: GATHER)                  |    500 |    1142 | 886.74
  2 |    ->  Partition Iterator                     |    500 |    1142 | 700.50
  3 |       ->  Partitioned Seq Scan on bmsql_stock |    500 |    1142 | 700.50
(3 rows)

 Predicate Information (identified by plan id) 
-----------------------------------------------
   2 --Partition Iterator
         Iterations: 3
   3 --Partitioned Seq Scan on bmsql_stock
         Filter: ((s_w_id)::numeric = 59.1)
         Selected Partitions:  1..3
(5 rows)

实验总结

本实验通过分析分区表静态剪枝的行为、触发条件,了解数据库是如何使用静态剪枝对分区表进行查询优化的。当分区列使用静态谓词,若且符合剪枝条件,数据库可以通过静态剪枝只查找指定的分区,跳过其他分区的扫描,提高查询性能。由于静态剪枝需要分区列带有特定条件,可以通过调整表的分区方式、修改查询条件等,使得尽量多的业务场景查询能触发静态剪枝。

相关推荐
NineData9 小时前
NineData 迁移评估功能正式上线
数据库·dba
董董灿是个攻城狮10 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
NineData14 小时前
数据库迁移总踩坑?用 NineData 迁移评估,提前识别所有兼容性风险
数据库·程序员·云计算
赵渝强老师17 小时前
【赵渝强老师】PostgreSQL中表的碎片
数据库·postgresql
AI软著研究员17 小时前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish17 小时前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱18 小时前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
全栈老石21 小时前
拆解低代码引擎核心:元数据驱动的"万能表"架构
数据库·低代码
地平线开发者1 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮1 天前
大模型连载2:初步认识 tokenizer 的过程
算法