达梦数据库BLANK_PAD_MODE与SPACE_COMPARE_MODE参数解析
·
一、参数概述
1.1 BLANK_PAD_MODE(初始化参数)
| 属性 | 说明 |
|---|---|
| 参数类型 | 初始化参数 |
| 设置时机 | 仅能在实例初始化时指定 |
| 修改方式 | 不可动态修改,重建实例才能变更 |
| 默认值 | 0 |
| 作用 | 控制字符串比较时是否忽略尾部空格 |
取值含义:
- 0:比较时忽略尾部空格(兼容 Oracle 默认行为)
- 1 :比较时考虑尾部空格(ANSI 标准行为)
1.2 SPACE_COMPARE_MODE(静态配置参数)
| 属性 | 说明 |
|---|---|
| 参数类型 | 静态配置参数 |
| 设置时机 | 可通过 SP_SET_PARA_VALUE 修改 |
| 生效方式 | 修改后需重启数据库实例 |
| 默认值 | 0 |
| 作用 | 控制查询语句中字符串尾部空格是否参与比较 |
取值含义:
- 0:忽略尾部空格
- 1:尾部空格参与比较
二、测试环境准备
2.1 环境信息
-- 数据库版本
SELECT banner FROM v$version;
-- DM Database Server 64 V8
-- DB Version: 0x7000d
-- 测试服务器
-- OS: Linux 5.10.134-18.al8.x86_64
-- 架构: x86_64
2.2 创建测试表
-- 基础行为测试表
CREATE TABLE t_space_test (
id INT,
vc_col VARCHAR(10),
ch_col CHAR(10)
);
INSERT INTO t_space_test VALUES (1, 'DM', 'DM');
INSERT INTO t_space_test VALUES (2, 'DM ', 'DM ');
INSERT INTO t_space_test VALUES (3, ' DM', ' DM');
INSERT INTO t_space_test VALUES (4, ' DM ', ' DM ');
COMMIT;
-- 索引性能测试表
CREATE TABLE t_perf_test (
id INT,
code VARCHAR(20),
name VARCHAR(50)
);
-- 插入1000条测试数据,其中部分数据尾部带空格
INSERT INTO t_perf_test
SELECT level,
'C' || level || CASE WHEN mod(level,10)=0 THEN ' ' ELSE '' END,
'Name' || level
FROM dual
CONNECT BY level <= 1000;
COMMIT;
CREATE INDEX idx_perf_code ON t_perf_test(code);
CALL DBMS_STATS.GATHER_TABLE_STATS('SYSDBA', 'T_PERF_TEST', null, 100, TRUE, 'FOR ALL COLUMNS SIZE AUTO');
三、参数行为测试
3.1 场景一:BLANK_PAD_MODE=0 & SPACE_COMPARE_MODE=0
这是达梦数据库的默认配置组合。
查询结果:
-- VARCHAR 类型查询
SELECT COUNT(*) FROM t_space_test WHERE vc_col = 'DM'; -- 结果:2(匹配 'DM' 和 'DM ')
SELECT COUNT(*) FROM t_space_test WHERE vc_col = 'DM '; -- 结果:2(同上)
-- CHAR 类型查询
SELECT COUNT(*) FROM t_space_test WHERE ch_col = 'DM'; -- 结果:2
SELECT COUNT(*) FROM t_space_test WHERE ch_col = 'DM '; -- 结果:2
测试结论:
| 数据类型 | 条件 = DM | 条件 = DM+空格 | 说明 |
|---|---|---|---|
| VARCHAR | 2 条 | 2 条 | 忽略尾部空格 |
| CHAR | 2 条 | 2 条 | 忽略尾部空格 |
- 无论 VARCHAR 还是 CHAR,都忽略尾部空格
DM和DM(带空格)被视为相等
3.2 场景二:BLANK_PAD_MODE=0 & SPACE_COMPARE_MODE=1
修改 SPACE_COMPARE_MODE参数并重启数据库:
SP_SET_PARA_VALUE(2, 'SPACE_COMPARE_MODE', 1);
-- 重启数据库后生效
查询结果:
-- VARCHAR 类型查询
SELECT COUNT(*) FROM t_space_test WHERE vc_col = 'DM'; -- 结果:1(仅匹配 'DM')
SELECT COUNT(*) FROM t_space_test WHERE vc_col = 'DM '; -- 结果:1(仅匹配 'DM ')
-- CHAR 类型查询
SELECT COUNT(*) FROM t_space_test WHERE ch_col = 'DM'; -- 结果:2
SELECT COUNT(*) FROM t_space_test WHERE ch_col = 'DM '; -- 结果:2
测试结论:
| 数据类型 | 条件 = DM | 条件 = DM+空格 | 说明 |
|---|---|---|---|
| VARCHAR | 1 条 | 1 条 | 考虑尾部空格 |
| CHAR | 2 条 | 2 条 | 忽略尾部空格(不受参数影响) |
关键发现:
- SPACE_COMPARE_MODE=1 仅影响 VARCHAR类型
- CHAR 类型的空格处理不受此参数影响,始终忽略尾部空格
四、参数性能影响
4.1 问题场景
当满足以下三个条件时,会出现索引无法定位的问题:
- BLANK_PAD_MODE=0(实例初始化时设置)
- SPACE_COMPARE_MODE=1(动态修改后重启)
- 查询条件为等值匹配(=)且条件值为无尾部空格的字符串
当 BLANK_PAD_MODE=0 时,索引按照"忽略尾部空格"的规则排序存储C100 和 C100 (带空格)在索引中视为相同值,存储在一起。
当 SPACE_COMPARE_MODE=1 时,查询使用"考虑尾部空格"的比较规则C100 和 C100 (带空格)被视为不同值。
优化器无法在"忽略尾部空格的索引"中精确定位"考虑尾部空格的查询值",只能选择全索引扫描,然后在过滤条件中排除不符合的行。
4.2 场景复现
场景 A:SPACE_COMPARE_MODE=0
SELECT * FROM t_perf_test WHERE code = 'C100';
实际执行计划:
1 #NSET2: [1, 1, 112]
2 #PRJT2: [1, 1, 112]; exp_num(4), is_atom(FALSE)
3 #BLKUP2: [1, 1, 112]; IDX_PERF_CODE(T_PERF_TEST)
4 #SSEK2: [1, 1, 112]; scan_type(ASC), IDX_PERF_CODE(T_PERF_TEST) scan_range['C100','C100'], is_global(0)
使用 SSEK2(索引范围定位)
扫描范围精确到 [‘C100’,‘C100’]
查询结果:匹配 1 条记录(同时匹配了 C100 和 C100 )
场景 B:SPACE_COMPARE_MODE=1(问题场景)
SELECT * FROM t_perf_test WHERE code = 'C100';
实际执行计划:
1 #NSET2: [1, 1, 112]
2 #PRJT2: [1, 1, 112]; exp_num(4), is_atom(FALSE)
3 #BLKUP2: [1, 1, 112]; IDX_PERF_CODE(T_PERF_TEST)
4 #SLCT2: [1, 1, 112]; T_PERF_TEST.CODE = 'C100'
5 #SSCN: [1, 1, 112]; IDX_PERF_CODE(T_PERF_TEST); btr_scan(1); is_global(0)
使用 SSCN(索引全扫描)
增加 SLCT2 过滤节点
需扫描整个索引后过滤
查询结果:匹配 0 条记录(只精确匹配不带空格的 C100)
4.3 性能差异分析
| 指标 | SPACE_COMPARE_MODE=0 | SPACE_COMPARE_MODE=1 |
|---|---|---|
| 索引扫描方式 | SSEK2(范围定位) | SSCN(全扫描) |
| 扫描范围 | 精确定位 | 全表扫描 |
| 额外过滤节点 | 无 | SLCT2 |
| 数据量 1000 条时,SSCN 需扫描全部索引页,而 SSEK2 仅需扫描定位页,随数据量增长,SSCN 性能线性下降,SSEK2 保持常量,生产环境百万级数据表可能导致查询从毫秒级退化到秒级 |
五、总结
- BLANK_PAD_MODE=0 且 SPACE_COMPARE_MODE=1 会导致索引范围定位失效
- CHAR 类型始终忽略尾部空格,不受 SPACE_COMPARE_MODE 影响
- 建议保持 BLANK_PAD_MODE 和 SPACE_COMPARE_MODE 配置一致
- 若需修改空格处理行为,优先在实例初始化时通过 BLANK_PAD_MODE 设置
附录:测试脚本
-- 完整测试脚本
-- 1. 查看当前参数
SELECT CAST(BLANK_PAD_MODE() AS VARCHAR) AS blank_pad_mode;
SELECT PARA_VALUE FROM V$DM_INI WHERE PARA_NAME = 'SPACE_COMPARE_MODE';
-- 2. 创建测试表
CREATE TABLE t_test (id INT, vc VARCHAR(10), ch CHAR(10));
INSERT INTO t_test VALUES (1, 'A', 'A'), (2, 'A ', 'A ');
COMMIT;
-- 3. 测试查询
SELECT 'VARCHAR eq A' AS test, COUNT(*) FROM t_test WHERE vc = 'A';
SELECT 'VARCHAR eq A-space' AS test, COUNT(*) FROM t_test WHERE vc = 'A ';
SELECT 'CHAR eq A' AS test, COUNT(*) FROM t_test WHERE ch = 'A';
SELECT 'CHAR eq A-space' AS test, COUNT(*) FROM t_test WHERE ch = 'A ';
-- 4. 查看执行计划
EXPLAIN SELECT * FROM t_test WHERE vc = 'A';
更多推荐


所有评论(0)