注册
DM9 新特性探索之在线碎片整理技术测试方案 二【#达梦数据库 #达梦同行者征文】
专栏/技术分享/ 文章详情 /

DM9 新特性探索之在线碎片整理技术测试方案 二【#达梦数据库 #达梦同行者征文】

羽书飞影 2026/08/28 215 2 0
摘要

一、测试概述(测试版本:9.1.0.26)

1.1业务背景

表数据量较大、DML 操作频繁时,记录被频繁更新、删除,容易产生表数据页碎片,影响表的读写性能。传统碎片整理方式需要对表加锁,期间不允许并发查询与并发 DML,无法满足 7×24 小时业务连续性要求。
DM9 提供了在线碎片整理能力——通过系统函数 SP_REORGANIZE_INDEX_ONLINE 对指定索引进行在线空间整理,整理期间索引保持完全可用,支持并发执行查询、插入、更新、删除操作,从而解决传统方案导致的业务中断问题。

1.2测试目的

验证 DM9 在线碎片整理技术在以下五个维度的表现:
•功能正确性——索引碎片能否被有效回收,空间是否释放
•并发可用性——整理期间是否允许并发 DML 与查询,不锁表
•性能收益——整理前后全表扫描、索引扫描的效率改善情况
•索引可用性——整理期间索引状态是否保持 VALID,查询能否走索引
•权限控制——不同权限用户跨 Schema 操作是否被正确放行或拒绝

1.3测试范围

image.png

1.4环境要求

image.png

二、前置准备

2.1 创建测试表及索引

【步骤说明】在目标用户下创建测试用数据表及配套索引。
创建测试表空间(可选)

CREATE TABLESPACE test_ts DATAFILE 'test_ts.dbf' SIZE 1024 AUTOEXTEND ON NEXT 256 MAXSIZE 4096;

image.png
创建测试用户(可选,用于验证跨 Schema 权限)

CREATE USER test_user IDENTIFIED BY "Test123!" DEFAULT TABLESPACE test_ts;  
GRANT RESOURCE TO test_user;  
GRANT DBA TO test_user;

image.png
创建测试表及索引

CREATE TABLE test_user.test_fragmentation
    (
          id     NUMBER(10)   NOT NULL,
          batch_no  VARCHAR2(32),
          content   VARCHAR2(500),
          status   CHAR(1)     DEFAULT '0',
          create_time DATE      DEFAULT SYSDATE,
          CONSTRAINT pk_test_frag PRIMARY KEY(id)
    );

CREATE INDEX test_user.idx_test_batch ON test_user.test_fragmentation(batch_no);

CREATE INDEX test_user.idx_test_status ON test_user.test_fragmentation(status);

CREATE INDEX test_user.idx_test_ctime ON test_user.test_fragmentation(create_time );

2.2 批量构造基础数据

插入初始数据(建议 1000 万行以上以获得明显的碎片效果):

DECLARE
    v_batch_size    NUMBER := 998;
    v_total_rows    NUMBER := 9999999;
    v_start_id      NUMBER;
    v_batches       NUMBER;
BEGIN
    v_start_id := 1;
    v_batches  := CEIL(v_total_rows / v_batch_size);

    FOR i IN 1..v_batches LOOP
        INSERT INTO test_user.test_fragmentation(id, batch_no, content, status, create_time)
        SELECT v_start_id + (i - 1) * v_batch_size + LEVEL - 1,
               'BATCH_' || MOD(v_start_id + (i - 1) * v_batch_size + LEVEL - 1, 297),
               LPAD('CONTENT_', 230, 'X') || TO_CHAR(v_start_id + (i - 1) * v_batch_size + LEVEL - 1),
               CASE WHEN MOD(LEVEL, 30) = 0 THEN '0'
                    WHEN MOD(LEVEL, 27) = 21 THEN '1'
                    ELSE '2' END,
               SYSDATE - MOD(v_start_id + (i - 1) * v_batch_size + LEVEL - 1, 9125)
          FROM DUAL
         CONNECT BY LEVEL <= v_batch_size;

        COMMIT;

        IF MOD(i, 20) = 0 THEN
            DBMS_OUTPUT.PUT_LINE('已完成 ' || i || '/' || v_batches || ' 批');
        END IF;
    END LOOP;

    COMMIT;
    DBMS_OUTPUT.PUT_LINE('生成完成');
END;
/

image.png

2.3 模拟频繁 DML 制造碎片

通过以下三轮操作模拟业务频繁增删改场景,使表空间产生大量碎片。
第一轮:大量 UPDATE(随机更新约 30,000 次)

DECLARE    v_loop NUMBER := 35000;  BEGIN    FOR i IN 1..v_loop LOOP      UPDATE test_fragmentation        SET content = LPAD('UPDATED_', 420, 'X') || i       WHERE id IN (SELECT id FROM test_fragmentation SAMPLE(0.08));      COMMIT;    END LOOP;  END;  /

image.png
第二轮:大量 DELETE(每次删除约 60 行,共 8,000 次)

DECLARE    v_loop NUMBER := 8000;  BEGIN    FOR i IN 1..v_loop LOOP      DELETE FROM test_fragmentation       WHERE id IN (SELECT id FROM test_fragmentation SAMPLE(0.03))        AND ROWNUM <= 50;      COMMIT; END LOOP;  END;  /

image.png

第三轮:重新 INSERT 填充(加剧碎片化)

INSERT INTO test_fragmentation(id, batch_no, content, status, create_time)  SELECT LEVEL + 38000000,      'BATCH_REINSERT_' || MOD(LEVEL, 240),      LPAD('NEW_DATA_', 370, 'Y') || LEVEL,      '0',      SYSDATE  FROM DUAL  CONNECT BY LEVEL <= 1200000;  COMMIT;

image.png

三、碎片分析与整理前基线

3.1 查看段空间占用

整理前记录各对象的空间占用,作为后续回收效果的对比基准。

SELECT SEGMENT_NAME,
             BYTES / 1024 / 1024 AS size_mb,
                                    BLOCKS,
                                    EXTENTS
    FROM DBA_SEGMENTS
   WHERE OWNER =  'TEST_USER' AND SEGMENT_NAME IN ('TEST_FRAGMENTATION',
                                            'PK_TEST_FRAG',
                                                        'IDX_TEST_BATCH',
                                            'IDX_TEST_STATUS',
                                                        'IDX_TEST_CTIME')
ORDER BY SEGMENT_TYPE,
         SEGMENT_NAME;

image.png

3.3 查询性能基线

全表扫描基线

SELECT COUNT(*), MAX(create_time) FROM test_fragmentation WHERE status = '1';

image.png

索引范围扫描基线

SELECT COUNT(*), MIN(id), MAX(id)  FROM test_fragmentation  WHERE batch_no = 'BATCH_1'   AND create_time >= SYSDATE - 545;

image.png
查看执行计划
image.png

四、核心测试用例

4.1 基本在线碎片整理(单索引)

用例编号: TC-ONLINE-001
测试目标: 验证对单个索引执行在线碎片整理的基本功能
前提条件: 表已产生明显碎片,聚簇因子偏高
执行 SQL:

SP_REORGANIZE_INDEX_ONLINE('TEST_USER','IDX_TEST_BATCH');

验证 SQL:
– 验证索引状态

SELECT INDEX_NAME, STATUS, LAST_ANALYZED  FROM DBA_INDEXES WHERE OWNER = 'TEST_USER' AND INDEX_NAME = 'IDX_TEST_BATCH';

image.png
– 验证查询仍能走索引

EXPLAIN   SELECT * FROM test_fragmentation WHERE batch_no = 'BATCH_1';  

image.png
✓ 预期结果:函数执行成功,索引状态为 VALID,查询仍走索引。

4.2 在线整理主键索引

用例编号: TC-ONLINE-002
测试目标 : 验证主键索引也能被在线整理,约束不受影响
前提条件: 同 4.1,主键索引已产生碎片
执行 SQL:

SP_REORGANIZE_INDEX_ONLINE(USER, 'PK_TEST_FRAG');

验证 SQL:

SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, STATUS  FROM DBA_CONSTRAINTS  WHERE OWNER = USER AND TABLE_NAME = 'TEST_FRAGMENTATION'   AND CONSTRAINT_NAME = 'PK_TEST_FRAG';

image.png
✓ 预期结果:主键索引整理成功,约束状态仍为 ENABLED。

4.3 整理期间并发 DML 验证(关键测试)

用例编号: TC-CONCUR-001
测试目标: 验证在线整理期间表可被正常并发读写,不锁表
测试方法: 双会话并行操作
优先级别: <run bold=“true” color=“C00000”>P0 - 核心功能</run>
会话 A —— 启动在线整理:

SELECT SYSDATE AS start_time FROM DUAL;
SP_REORGANIZE_INDEX_ONLINE(USER, 'IDX_TEST_STATUS');
SELECT SYSDATE AS end_time FROM DUAL;

image.png
会话 B —— 整理过程中并发执行:

SELECT COUNT(*), status, MAX(create_time) FROM test_fragmentation WHERE status = '2' GROUP BY status;

image.png
– 并发 INSERT

INSERT INTO test_fragmentation(id, batch_no, content, status, create_time) VALUES (99999999, 'CONCUR_TEST', 'Online reorg concurrent insert', '0', SYSDATE);
COMMIT;

==-- 并发 UPDATE ==

UPDATE test_fragmentation  SET content = 'Concurrently updated during online reorg'  WHERE id = 99999999;  
COMMIT;

==-- 并发DELETE ==

DELETE  DELETE FROM test_fragmentation WHERE id = 99999999;  
COMMIT;

✓ 预期结果:会话A整理期间,会话B所有 DML 与查询均立即成功,无锁等待。

4.4 长时间整理压力测试

用例编号: TC-CONCUR-002
测试目标: 大表在线整理时,持续写入不中断
优先级别: <run bold=“true” color=“C00000”>P0 - 核心功能</run>
执行 SQL:

DECLARE    v_base_id NUMBER;  BEGIN    FOR i IN 1..100 LOOP      SELECT NVL(MAX(id), 0) + 1 INTO v_base_id FROM test_fragmentation;      INSERT INTO test_fragmentation(id, batch_no, content, status, create_time)      VALUES (v_base_id, 'STRESS_' || i, LPAD('STRESS_TEST_DATA', 480, 'Z'),          CASE WHEN MOD(i, 2) = 0 THEN '1' ELSE '2' END, SYSDATE);      COMMIT;      UPDATE test_fragmentation        SET status = CASE WHEN status = '1' THEN '2' ELSE '1' END       WHERE id IN (SELECT id FROM test_fragmentation SAMPLE(0.005));      COMMIT;      DBMS_LOCK.SLEEP(0.1);    END LOOP;  END;  /

image.png
✓ 预期结果:并发无阻塞,所有 DML 正常提交。

4.5 跨 Schema 权限验证

用例编号: TC-PERM-001
测试目标: DBA / DB_OBJECT_ADMIN 可整理他人索引;普通用户不能
场景A — DBA 用户执行(预期成功):

SP_REORGANIZE_INDEX_ONLINE('TEST_USER', 'IDX_TEST_BATCH');

image.png
场景B — 普通用户跨 Schema(预期报错):

SP_REORGANIZE_INDEX_ONLINE('SYSDBA', 'IDX_FTB_V_CPTY_EXINFO');

image.png
✓ 预期结果:场景A 成功执行;场景B 报错。

五、整理后效果验证

5.1 空间回收对比

对比整理前后的段空间占用,评估碎片回收效率。

SELECT SEGMENT_NAME,
             BYTES / 1024 / 1024 AS size_mb,
                                    BLOCKS,
                                    EXTENTS
    FROM DBA_SEGMENTS
   WHERE OWNER =  'TEST_USER' AND SEGMENT_NAME IN ('TEST_FRAGMENTATION',
                                            'PK_TEST_FRAG',
                                                        'IDX_TEST_BATCH',
                                            'IDX_TEST_STATUS',
                                                        'IDX_TEST_CTIME')
ORDER BY SEGMENT_TYPE,
         SEGMENT_NAME;

–执行在线整理,执行完索引水位线无变化
SP_REORGANIZE_INDEX_ONLINE(‘TEST_USER’,‘IDX_TEST_BATCH’);
SP_REORGANIZE_INDEX_ONLINE(‘TEST_USER’,‘IDX_TEST_STATUS’);
SP_REORGANIZE_INDEX_ONLINE(‘TEST_USER’,‘IDX_TEST_CTIME’);
SP_REORGANIZE_INDEX_ONLINE(‘TEST_USER’,‘INDEX33555530’);
image.png

–执行SP_REBUILD_INDEX,索引占用水位线已经下降

SP_REBUILD_INDEX('TEST_USER', '33555531');
SP_REBUILD_INDEX('TEST_USER', '33555533');
SP_REBUILD_INDEX('TEST_USER', '33555532');
SP_REBUILD_INDEX('TEST_USER', '33555529');
SP_REBUILD_INDEX('TEST_USER', '33555530');

image.png

5.3 查询性能对比

全表扫描耗时对比

SELECT COUNT(*), MAX(create_time) FROM test_fragmentation WHERE status = '1';

image.png
索引扫描耗时对比

SELECT COUNT(*), MIN(id), MAX(id)  FROM test_fragmentation  WHERE batch_no = 'BATCH_1' AND create_time >= SYSDATE - 1095;

image.png
查看执行计划

EXPLAIN  SELECT COUNT(*), MAX(create_time) FROM test_fragmentation WHERE status = '1';  

image.png

六、测试总结

image.png

七、注意事项与风险

备份先行:生产环境测试前务必做好数据备份,以防万一。
监控归档日志:在线整理会产生大量 UNDO / REDO,需确保归档空间充足。
观察锁等待:整理期间可通过 SELECT * FROM V$LOCK 实时监控是否有锁冲突。
分批执行:大表建议逐个索引分批整理,避免单次事务日志暴增。
及时收集统计信息:整理完毕后务必重新收集统计信息,确保优化器有准确的数据。
整理后建议执行:DBMS_STATS.GATHER_TABLE_STATS(USER, ‘TEST_FRAGMENTATION’, CASCADE => TRUE);

八、附录 — 函数签名速查

image.png

【#达梦数据库 #达梦同行者征文】

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服