实验五 静态剪枝

概念介绍

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

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

实验总结

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

相关推荐
银发控、7 小时前
MySQL联合索引
数据库·mysql
予枫的编程笔记7 小时前
【MySQL修炼篇】从踩坑到精通:事务隔离级别的3大异常(脏读/幻读/不可重复读)解决方案
数据库·mysql·后端开发·数据库事务·事务隔离级别·rr级别·脏读幻读不可重复读
数研小生9 小时前
构建命令行单词记忆工具:JSON 词库与艾宾浩斯复习算法的完美结合
算法·json
芒克芒克9 小时前
LeetCode 题解:除自身以外数组的乘积
算法·leetcode
一起养小猫9 小时前
Flutter for OpenHarmony 实战:记账应用数据统计与可视化
开发语言·jvm·数据库·flutter·信息可视化·harmonyos
世界尽头与你9 小时前
(修复方案)CVE-2023-22047: Oracle PeopleSoft Enterprise PeopleTools 未授权访问漏洞
数据库·安全·oracle·渗透测试
韩立学长9 小时前
【开题答辩实录分享】以《智能大学宿舍管理系统的设计与实现》为例进行选题答辩实录分享
数据库·spring boot·后端
Python 老手9 小时前
Python while 循环 极简核心讲解
java·python·算法
Henry Zhu1239 小时前
数据库(五):反规范化
数据库
@Aurora.9 小时前
优选算法【专题九:哈希表】
算法·哈希算法·散列表