一、参数概述

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+空格说明
VARCHAR2 条2 条忽略尾部空格
CHAR2 条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+空格说明
VARCHAR1 条1 条考虑尾部空格
CHAR2 条2 条忽略尾部空格(不受参数影响)

关键发现:

  • SPACE_COMPARE_MODE=1 仅影响 VARCHAR类型
  • CHAR 类型的空格处理不受此参数影响,始终忽略尾部空格

四、参数性能影响

4.1 问题场景

当满足以下三个条件时,会出现索引无法定位的问题:

  1. BLANK_PAD_MODE=0(实例初始化时设置)
  2. SPACE_COMPARE_MODE=1(动态修改后重启)
  3. 查询条件为等值匹配(=)且条件值为无尾部空格的字符串

当 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=0SPACE_COMPARE_MODE=1
索引扫描方式SSEK2(范围定位)SSCN(全扫描)
扫描范围精确定位全表扫描
额外过滤节点无SLCT2
数据量 1000 条时,SSCN 需扫描全部索引页,而 SSEK2 仅需扫描定位页,随数据量增长,SSCN 性能线性下降,SSEK2 保持常量,生产环境百万级数据表可能导致查询从毫秒级退化到秒级

五、总结

  1. BLANK_PAD_MODE=0 且 SPACE_COMPARE_MODE=1 会导致索引范围定位失效
  2. CHAR 类型始终忽略尾部空格,不受 SPACE_COMPARE_MODE 影响
  3. 建议保持 BLANK_PAD_MODE 和 SPACE_COMPARE_MODE 配置一致
  4. 若需修改空格处理行为,优先在实例初始化时通过 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';
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐