注册
绑定参数时数据倾斜度较大的解决办法
专栏/龙山溪笔谈/ 文章详情 /

绑定参数时数据倾斜度较大的解决办法

myth8860 2025/09/06 123 1 0
摘要 数据倾斜度较大时,绑定参数的方式有时会走错误的执行计划,导致性能问题。

在日常数据库查询中,like模糊查询是非常常见的操作。但当数据量达到百万级别,且字段数据分布存在严重倾斜时,如何保证查询性能就成了一个值得关注的问题。今天我们就通过一个实际案例,来看看达梦数据库优化器是如何智能处理这种情况的!

测试环境搭建
首先我们创建一个测试表,并插入100万条模拟数据:

drop table if exists TEST_LIKE;
create TABLE test_like (
    name VARCHAR(100),  -- 姓名
    sfz VARCHAR(20)     -- 身份证号
);

INSERT INTO test_like (name, sfz)
SELECT 
    -- 随机姓名(姓氏+1-2字名)
    SUBSTR(base.surnames, FLOOR(DBMS_RANDOM.VALUE(1, 61)), 1)  -- 随机姓氏(60选1)
    || SUBSTR(base.first_names, FLOOR(DBMS_RANDOM.VALUE(1, 81)), 1)  -- 随机名首字(80选1)
    || CASE WHEN DBMS_RANDOM.VALUE(0, 1) > 0.5  -- 50%概率增加次字(40选1)
            THEN SUBSTR(base.second_names, FLOOR(DBMS_RANDOM.VALUE(1, 41)), 1) 
            ELSE '' END AS name,
    -- 身份证号(18位:固定前缀+有效日期+随机4位)
    '421125'  -- 前6位固定(湖北省黄冈市浠水县)
    || TO_CHAR(  -- 中间8位:1900-2005年随机有效日期
        base.start_date + FLOOR(DBMS_RANDOM.VALUE(0, DATEDIFF(DAY, base.start_date, base.end_date) + 1)), 
        'YYYYMMDD'
      )
    || LPAD(FLOOR(DBMS_RANDOM.VALUE(0, 10000)), 4, '0')  -- 后4位:0000-9999随机数
    AS sfz
FROM 
    -- 1. 生成100万行序号(CONNECT BY替代递归CTE)
    (SELECT LEVEL AS n FROM dual CONNECT BY LEVEL <= 1000000) num_seq,
    -- 2. 基础数据常量(姓名用字+日期范围)
    (SELECT 
        '赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞任袁柳' AS surnames,  -- 60个常见姓氏
        '伟芳娜秀英敏静丽娟英华慧巧美静文萍玲芳燕敏玲晓锋刚勇毅俊峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元' AS first_names,  -- 80个常用名首字
        '伟芳娜秀英敏静丽娟英华慧巧美静文萍玲芳燕敏玲晓锋刚勇毅俊峰强军平保东文辉力明' AS second_names,  -- 40个常用名次字
        TO_DATE('1900-01-01', 'YYYY-MM-DD') AS start_date,  -- 出生日期起始(1900年)
        TO_DATE('2005-12-31', 'YYYY-MM-DD') AS end_date     -- 出生日期截止(2005年,确保年龄合理性)
     FROM dual) base;

我们在身份证号字段上创建索引,更新统计信息:

create index idx_sfz_test_like on test_like(sfz);
stat 100 on test_like(sfz);

数据分布特点分析

这个测试表有一个重要特点:所有身份证号都以"421125"开头!这意味着:

  • 如果使用like '421125%'查询,会匹配所有100万行数据
  • 如果使用like '4211252000%'查询,只会匹配2000年出生的部分数据

优化器的智能选择
现在我们来执行两个类似的查询,但参数不同:

select /*+PLAN_NO_CACHE BEXP_CALC_ST_FLAG(128)*/  *     from TEST_LIKE where sfz like ?;

--输入参数:421125%  ,查看实际的执行计划

1dc18e302dc0793510483ee1811d2351.png

100万行数据全匹配,这个时候执行计划走了全表扫描

--输入参数:4211252000%  ,查看实际的执行计划
fccf5f674195315b5e4130d161c4bc90.png
匹配到9505条数据,这个时候走索引扫描更合理

关键参数
达梦优化器通过以下两个参数实现最优的执行计划:
PLAN_NO_CACHE:不重用计划,生成新的执行计划BEXP_CALC_ST_FLAG:128表示对列与绑定参数之间的过滤条件表达式通过统计信息直方图方式计算选择率

结语

通过这个案例,我们看到了达梦优化器在处理数据分布倾斜时的智能表现。它能够根据具体的查询条件选择性使用索引,既避免了在需要大量数据时的无效索引扫描,又在真正需要时充分利用索引加速查询。这只适用于数据严重倾斜的场景,建议使用HINT的方式将这两个参数成对使用,PLAN_NO_CACHE会造成硬解析。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服