实验五 静态剪枝

概念介绍

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

分区剪枝是被动触发的,一般情况下,当查询 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)

实验总结

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

相关推荐
蒋士峰DBA修行之路2 小时前
实验六 动态剪枝
数据库·算法·剪枝
kimble_xia@oracle2 小时前
SQL 笔记
java·数据库·oracle
Tim_102 小时前
【算法专题训练】20、LRU 缓存
c++·算法·缓存
B612 little star king3 小时前
力扣29. 两数相除题解
java·算法·leetcode
野犬寒鸦3 小时前
力扣hot100:环形链表(快慢指针法)(141)
java·数据结构·算法·leetcode·面试·职场和发展
时光追逐者3 小时前
C# 哈希查找算法实操
算法·c#·哈希算法
树谷-胡老师3 小时前
公元前3400年至公元2024年全球国家地理边界演变数据集
数据库·arcgis·信息可视化
疯狂的Alex3 小时前
2010-2022 同等学力申硕国考:软件工程简答题真题汇总
数据库·oracle·软件工程
Qlittleboy3 小时前
tp5的tbmember表闭包查询 openid=‘abc‘ 并且(wx_unionid=null或者wx_unionid=‘‘)
数据库·sql·php