暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

达梦 DM9 新特性实测:性能惊艳,但一个参数却把实例打崩了

108

大家好,我是 JiekeXu,江湖人称“强哥”,青学会MOP技术社区主席,荣获Oracle ACE Pro称号,OpenTenBase ACE,金仓社区最具价值倡导者KVA,崖山最具价值专家YVP,IvorySQL开源社区专家顾问委员会成员,KWDB社区MVP,墨天轮MVP,墨天轮连续多年度“墨力之星”,拥有Oracle OCP/OCM认证,MySQL 5.7/8.0 OCP认证以及金仓KCA、KCP、KCM、KCSM证书,TiDB PCTA/PCTP证书、PCA、OBCA、OGCA等众多国产数据库认证证书,专注于数据库技术、系统架构及大数据运维,致力于分享最纯粹、最接地气的 DBA 实战与前沿技术洞察。如果你也对数据技术充满热忱,欢迎关注我的微信公众号“JiekeXu DBA之路”点赞、转发与评论,谢谢!

前 言

今年 4 月份很荣幸受邀参加了达梦数据库的新品发布会,会上发布了达梦一体机、达梦 9 ,达梦启云 V4 以及达梦图数据库等,也写了一篇文章《七年磨一剑!达梦 DM9 重磅发布,深挖技术白皮书看看都有啥?》。DM9 发布也号称有 450+ 新特性,所以一直想着体验测试一下,奈何发不了大半年达梦一直没有公布官方下载地址(https://www.dameng.com/download/index.html),也没有任何关于 DM9 的官方文档公布,手里只有 4 月份私发给我的 DM9 技术白皮书,故本次也就是基于这个仅有的白皮书和 DM9 开发版安装介质,摸着石头过河体验测试一下 DM9 在单机环境下都有哪些新特性。

当然官方号称有 450+ 的新特性,这里肯定连十分之一都体验不到,只是重点关注白皮书中提到的 第四章 高性能优化、第六章 AI 原生与智能化 相关的特性和能力,文中若有不足及错误之处,欢迎私信交流。

图片.png

达梦数据库 DM9 新特性体验测试

图片.png

项目 详情
测试版本 DM Database Server 64 V9(Build: 03151060506-20260417-322930-20218,DB Version: 0x7000d)
测试日期 2026-09-24
测试环境 单机 NORMAL 模式(实例 DMSERVER),主机 192.168.221.152,端口 15236,安装路径 /data/DM9/dmdbms
连接方式 env -u LD_LIBRARY_PATH ssh -p 62022 dmdba@192.168.221.152 → disql -L -S /@127.0.0.1:15236 AS SYSDBA;SQL 经 base64 管道传输
测试方法 全部 SQL 逐条实际执行并捕获输出;所有对象(表空间/用户/表/索引/数据)均通过 SQL 创建与装载
重点体验 白皮书 第四章 高性能优化、第六章 AI 原生与智能化);其余章节约取单机可体验特性

说明:DM9 核心宣传点"集中分布一体化 3.0"(DSC/DPC)、“AFC 自治容灾”、多租户等属集群/产品级特性,本次为单机 NORMAL 模式环境无法直接体验,仅能在参数与视图层面佐证其存在。本次测试聚焦单机可验证部分,所有结论均有实际执行输出支撑。


0. 环境准备

0.1 操作系统资源简介

使用 x86 虚拟机红帽 9.6 操作系统,8c 16G 190GB 磁盘安装 DM9 单机数据库,数据库安装使用 DMShellInstallV5.3.0 版本安装。

执行命令:

[dmdba@JiekeXu:/home/dmdba]$ df -h 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 7.7G 0 7.7G 0% /dev tmpfs 7.7G 1.2M 7.7G 1% /dev/shm tmpfs 3.1G 310M 2.8G 10% /run efivarfs 256K 30K 222K 12% /sys/firmware/efi/efivars /dev/mapper/rootvg-lvroot 190G 83G 108G 44% / /dev/sda2 2.0G 427M 1.6G 22% /boot /dev/sda1 200M 7.1M 193M 4% /boot/efi tmpfs 1.6G 0 1.6G 0% /run/user/0 tmpfs 1.6G 0 1.6G 0% /run/user/56781 tmpfs 1.6G 0 1.6G 0% /run/user/2222 [dmdba@JiekeXu:/home/dmdba]$ uname -a Linux JiekeXu 5.14.0-687.10.1.el9_8.x86_64 #1 SMP PREEMPT_DYNAMIC Mon May 18 15:13:25 EDT 2026 x86_64 x86_64 x86_64 GNU/Linux [dmdba@JiekeXu:/home/dmdba]$ cat /proc/cpuinfo | grep cores |wc -l 8 [dmdba@JiekeXu:/home/dmdba]$ cat /etc/redhat-release Red Hat Enterprise Linux release 9.6 (Plow) [dmdba@JiekeXu:/home/dmdba]$ free -h total used free shared buff/cache available Mem: 15Gi 9.7Gi 2.7Gi 4.3Gi 9.6Gi 5.7Gi Swap: 15Gi 118Mi 15Gi

0.2 DM9 数据库单机一键安装及版本查看验证

[root@JiekeXu soft]# sh DMShellInstall -di dm9_20260514_x86_centos7_64.iso -d /data/DM9/dmdbms -pn 15236 -dd /data/DM9/dmdata -ad /data/DM9/dmarch -bd /data/DM9/dmbak -cd /data/DM9/dmbak/core -sp 'Sysdba_123' ███████ ████ ████ ████████ ██ ██ ██ ██ ██ ██ ██ ░██░░░░██ ░██░██ ██░██ ██░░░░░░ ░██ ░██ ░██░██ ░██ ░██ ░██ ░██ ░██░██░░██ ██ ░██░██ ░██ █████ ░██ ░██░██ ███████ ██████ ██████ ██████ ░██ ░██ ░██ ░██░██ ░░███ ░██░█████████░██████ ██░░░██ ░██ ░██░██░░██░░░██ ██░░░░ ░░░██░ ░░░░░░██ ░██ ░██ ░██ ░██░██ ░░█ ░██░░░░░░░░██░██░░░██░███████ ░██ ░██░██ ░██ ░██░░█████ ░██ ███████ ░██ ░██ ░██ ██ ░██ ░ ░██ ░██░██ ░██░██░░░░ ░██ ░██░██ ░██ ░██ ░░░░░██ ░██ ██░░░░██ ░██ ░██ ░███████ ░██ ░██ ████████ ░██ ░██░░██████ ███ ███░██ ███ ░██ ██████ ░░██ ░░████████ ███ ███ ░░░░░░░ ░░ ░░ ░░░░░░░░ ░░ ░░ ░░░░░░ ░░░ ░░░ ░░ ░░░ ░░ ░░░░░░ ░░ ░░░░░░░░ ░░░ ░░░ 恭喜!单机安装成功,现在是否继续关闭数据库并重启主机? [Y/N] N 操作已取消,请手动重启 [root@JiekeXu soft]# su - dmdba [dmdba@JiekeXu:/home/dmdba]$ ds Server[127.0.0.1:15236]:mode is normal, state is open login used time : 4.775(ms) 密钥过期时间:2027-04-17 disql V9 20:45:36 dmdba SQL> set time off dmdba SQL> SELECT * FROM v$version; BANNER --------------------------------- DM Database Server 64 V9 DB Version: 0x7000d 03151060506-20260417-322930-20218 Msg Version: 3 Gsu level(5) cnt: 102 used time: 0.500(ms). Execute id is 1503. dmdba SQL> SELECT ID_CODE, BUILD_TYPE, TO_NUMBER(SUBSTR(VER,1,2),'XX')||'.'|| TO_NUMBER(SUBSTR(VER,3,2),'XX')||'.'|| TO_NUMBER(SUBSTR(VER,5,2),'XX')||'.'|| TO_NUMBER(SUBSTR(VER,7,2),'XX') AS INNER_VISION FROM ( SELECT DECODE(SUBSTR(CODE,1,2),'03','企业版','05','安全版','02','标准版','其他') AS BUILD_TYPE, RAWTOHEX(CAST(SUBSTR(CODE,3) AS INT)) AS VER, ID_CODE FROM ( SELECT ID_CODE, REGEXP_SUBSTR(ID_CODE,'[^-]+',1,1) AS CODE ) ); ID_CODE BUILD_TYPE INNER_VISION ----------------------------------- ---------- ------------ --03151060506-20260417-322930-20218 企业版 9.1.0.26 dmdba SQL> select name,mode$,status$ FROM v$instance; NAME MODE$ STATUS$ -------- ------ ------- DMSERVER NORMAL OPEN used time: 0.564(ms). Execute id is 1504. dmdba SQL> dmdba SQL> dmdba SQL> exit [dmdba@JiekeXu:/home/dmdba]$

image.png

0.3 创建测试表空间及用户授权

SQL:

CREATE TABLESPACE "TS_PERF" DATAFILE '/data/DM9/dmdata/DAMENG/TS_PERF01.DBF' SIZE 128 AUTOEXTEND ON NEXT 32 MAXSIZE 8192 CACHE = NORMAL; CREATE TABLESPACE "TS_AI" DATAFILE '/data/DM9/dmdata/DAMENG/TS_AI01.DBF' SIZE 128 AUTOEXTEND ON NEXT 16 MAXSIZE 4096 CACHE = NORMAL;

创建测试用户并授权。

SQL:

CREATE USER "DM9_TEST" IDENTIFIED BY "Dm9#Test2026" DEFAULT TABLESPACE "TS_PERF" DEFAULT INDEX TABLESPACE "TS_PERF"; GRANT RESOURCE, PUBLIC TO "DM9_TEST"; GRANT CREATE PROCEDURE, CREATE TRIGGER, CREATE VIEW, CREATE SEQUENCE TO "DM9_TEST"; ALTER USER "DM9_TEST" IDENTIFIED BY "Dm9Test_2026"; ALTER USER "DM9_TEST" QUOTA UNLIMITED ON "TS_AI";

0.4 创建测试表并批量插入数据

SQL:

-- T_SALES:销售事实表(含 4 个二级索引列) CREATE TABLE T_SALES ( SALE_ID INT, CUST_ID INT, PROD_ID INT, CHANNEL_ID INT, REGION_ID INT, SALE_DATE DATE, QTY INT, AMOUNT DECIMAL(12,2), DISCOUNT INT ) STORAGE(ON "TS_PERF", CLUSTERBTR); CREATE TABLE: executed successfully, used time: 32.044(ms). Execute id is 3901. INSERT INTO T_SALES SELECT LEVEL, MOD(LEVEL-1, 200000)+1, MOD((LEVEL-1)*7, 10000)+1, MOD(LEVEL-1, 4)+1, MOD(LEVEL-1, 13)+1, ADD_DAYS(TO_DATE('2025-01-01','YYYY-MM-DD'), MOD(LEVEL-1, 730)), MOD(LEVEL-1, 50)+1, ROUND(RAND(LEVEL)*1000, 2), MOD(LEVEL-1, 20)*3 FROM DUAL CONNECT BY LEVEL <= 1000000; INSERT: affect rows 1000000, used time: 949.973(ms). Execute id is 3902.

体验点(批量装载性能):100 万行通过单条 INSERT ... SELECT CONNECT BY 插入仅耗时 950 ms,约 105 万行/秒。这是第 1 章"批量流水线(Batch Pipeline)"能力的直接体现(批量组装 BATCH_INSERT_ROWS、批量数据包 BDTA、批量提交 COMMIT_BATCH)。同批另建 50 万行宽表 T_WIDE 插入仅 1.44 s;其余数据装载性能见第 1.1 节汇总表。


1. 高性能(Performance)优化 —— 重点体验

1.1 批量流水线(Batch Pipeline)装载

测试目标:验证白皮书"批量流水线"装载能力。方法:用单条 INSERT ... SELECT ... CONNECT BY 大规模造数,观察装载耗时与相关 I

第 1 步 建事实表 T_SALES 并装载 100 万行(9 列含日期/金额/折扣,存储于 TS_PERF)

-- 以 DM9_TEST 用户执行 CREATE TABLE T_SALES ( SALE_ID INT, CUST_ID INT, PROD_ID INT, CHANNEL_ID INT, REGION_ID INT, SALE_DATE DATE, QTY INT, AMOUNT DECIMAL(12,2), DISCOUNT INT ) STORAGE(ON "TS_PERF", CLUSTERBTR); INSERT INTO T_SALES SELECT LEVEL, MOD(LEVEL-1, 200000)+1, MOD((LEVEL-1)*7, 10000)+1, MOD(LEVEL-1, 4)+1, MOD(LEVEL-1, 13)+1, ADD_DAYS(TO_DATE('2025-01-01','YYYY-MM-DD'), MOD(LEVEL-1, 730)), MOD(LEVEL-1, 50)+1, ROUND(RAND(LEVEL)*1000, 2), MOD(LEVEL-1, 20)*3 FROM DUAL CONNECT BY LEVEL <= 1000000;

实际输出:

CREATE TABLE: executed successfully, used time: 32.044(ms). Execute id is 3901.
INSERT:       affect rows 1000000,  used time: 949.973(ms). Execute id is 3902.

第 2 步 建 4 个二级索引 + 宽表 T_WIDE 并装载 50 万行(12 列混合类型,覆盖 INT/VARCHAR/DECIMAL/DATE ×3 组)

CREATE INDEX IDX_SALES_CUST ON T_SALES(CUST_ID) STORAGE(ON "TS_PERF"); CREATE INDEX IDX_SALES_PROD ON T_SALES(PROD_ID) STORAGE(ON "TS_PERF"); CREATE INDEX IDX_SALES_REGION ON T_SALES(REGION_ID) STORAGE(ON "TS_PERF"); CREATE INDEX IDX_SALES_DATE ON T_SALES(SALE_DATE) STORAGE(ON "TS_PERF"); CREATE TABLE T_WIDE ( C01 INT, C02 VARCHAR(50), C03 DECIMAL(12,2), C04 DATE, C05 INT, C06 VARCHAR(50), C07 DECIMAL(12,2), C08 DATE, C09 INT, C10 VARCHAR(50), C11 DECIMAL(12,2), C12 DATE ) STORAGE(ON "TS_PERF", CLUSTERBTR); INSERT INTO T_WIDE SELECT LEVEL, 'NAME-'||LEVEL, ROUND(RAND(LEVEL)*9999.99,2), ADD_DAYS(DATE '2020-01-01', MOD(LEVEL,2000)), MOD(LEVEL,1000)+1, 'CITY-'||MOD(LEVEL,500), ROUND(RAND(LEVEL+7)*9999.99,2), ADD_DAYS(DATE '2021-06-01', MOD(LEVEL,1500) MOD(LEVEL,200)+1, 'TAG-'||MOD(LEVEL,777), ROUND(RAND(LEVEL*3)*9999.99,2), ADD_DAYS(DATE '2022-01-01', MOD(LEVEL,1000)) FROM DUAL CONNECT BY LEVEL <= 500000; COMMIT;

实际输出(依次对应上面 4 索引 + 建表 + 插数 + 提交):

used time: 421.150(ms). Execute id is 4001.   ← IDX_SALES_CUST
used time: 538.300(ms). Execute id is 4002.   ← IDX_SALES_PROD
used time: 640.546(ms). Execute id is 4003.   ← IDX_SALES_REGION
used time: 783.476(ms). Execute id is 4004.   ← IDX_SALES_DATE
used time: 25.804(ms).  Execute id is 4005.   ← CREATE TABLE T_WIDE
affect rows 500000, used time: 00:00:01.443.  Execute id is 4006.  ← INSERT
executed successfully, used time: 3.167(ms).  Execute id is 4007.  ← COMMIT

第 3 步 验证行数(装载结果落账确认)

SELECT 'T_SALES' AS TN, COUNT(*) AS CNT FROM T_SALES UNION ALL SELECT 'T_WIDE', COUNT(*) FROM T_WIDE;
TN      CNT
T_SALES 1000000
T_WIDE  500000
(used time: 1.013(ms). Execute id is 4010.)

第 4 步 批量参数:要不要调整?怎么查?

批量流水线相关 INI 参数在 VPARAMETER/VPARAMETER / VDM_INI 中直接可查(本步实测值):

参数 实测值 作用 本步是否调整
COMMIT_BATCH 1 批提交开关(1=开启) 不需要——出厂即开启,装载性能已体现
BATCH_INSERT_ROWS 10 批量组装的行数 不需要——CONNECT BY 生成的结果集按批流水线装配,默认值已足够
COMMIT_BATCH_TIMEOUT 1000 提交批刷日志等待时间(μs) 不需要——默认 1000μs 的组提交是 100 万行/0.95s 的关键
BDTA_PACKAGE_COMPRESS (存在) 批量数据包压缩开关 不需要——本场景无网络传输,关闭/开启不影响本机装载

结论:本步完全没有修改任何参数——白皮书所描述的"批量流水线"(批量组装 BATCH_INSERT_ROWS → 批量数据包 BDTA → 批量提交 COMMIT_BATCH)在出厂默认配置下即可工作。若要在大结果集排序/聚合场景进一步体验批处理,可对会话执行 SP_SET_PARA_VALUE(2,'SORT_BATCH_LEVEL',1)(会话级动态修改,无需重启),本报告 1.4 节的并行实验就是同一机制(详见各节"参数调整"说明)。

第 5 步 装载性能汇总(全部为单条 INSERT … SELECT … FROM DUAL CONNECT BY,未开并行、未改任何参数):

场景 规模 耗时 速率
T_SALES 事实表(9 列+计算列) 100 万行 949.973 ms 105 万行/秒
T_WIDE 宽表(12 列混合类型) 50 万行 1.44 s 34.7 万行/秒
T_VEC_BIG 向量表(16 维 FLOAT32 向量解析,见 2.2) 50 万行 6.709 s 7.5 万行/秒
T_SALES 追加装载(与在线备份并发执行,见 3.4) 20 万行 3.674 s 5.4 万行/秒

小结:一条 INSERT ... SELECT ... CONNECT BY 装载 100 万行仅 950ms(≈105 万行/秒),无需调整任何参数即拿到批量流水线效果;相关参数全部可在 V$ PARAMETER 中验证与查询。装载速度随行的"宽度"(12 列宽表 34.7 万行/秒)与"计算复杂度"(向量解析 7.5 万行/秒)合理衰减。3.4 节的"在线备份期间并发装载 20 万行成功"进一步证明批量流水线与无锁热备可叠加工作。

1.2 栈式虚拟机(Stack-based VM)执行器

测试目标:验证白皮书"栈式虚拟机执行器"存在性与速度。方法:建一个纯计算 PL/SQL 函数做循环基准(压测 VM 解释执行),并查询 VM 运行时视图 V$VMS 观察内部栈状态。

第 1 步 创建 INT 版基准函数

CREATE OR REPLACE FUNCTION DM9_TEST.F_BENCH(N INT) RETURN BIGINT AS S BIGINT := 0; BEGIN FOR I IN 1..N LOOP S := S+I; END LOOP; RETURN S; END; / SELECT DM9_TEST.F_BENCH(5000000) LOOP5M_RESULT FROM DUAL; SELECT DM9_TEST.F_BENCH(2000000) LOOP2M_RESULT FROM DUAL; SELECT DM9_TEST.F_BENCH(1000000) LOOP1M_RESULT FROM DUAL;

实际输出(三次调用耗时与规模线性一致,说明计时稳定):

executed successfully, used time: 29.536(ms).   ← CREATE OR REPLACE 本身
LOOP5M_RESULT = 12500002500000   used time: 995.369(ms)   ≈ 502 万次迭代/秒
LOOP2M_RESULT = 2000001000000    used time: 390.460(ms)   ≈ 512 万次迭代/秒
LOOP1M_RESULT = 500000500000     used time: 195.237(ms)   ≈ 512 万次迭代/秒

第 2 步 观察 VM 运行时状态(怎么查:V$VMS 视图)

SELECT * FROM V$VMS; select ID,VSTACK_SIZE,VTOP,VUSED,STKFRM_DEPTH,IP,N_FUNS from V$VMS;
ID  TRX_ID  STMT_ID  EXP_FLAG  VSTACK_SIZE  VSTACK            VTOP   VUSED  MEMOBJ
10  46097   0        N         1024         139698167895376   1022   2      139698167891416
STKFRM_DEPTH  FREE_STKFRMS  CURR_FRM          IP(指令指针)    RT_HEAP  SQL_NO  RS_SEQ_NO
1             0             139698167891544   139698167921416  -1       0       0
ECPT_CODE  ERR_DESC  ROW_AFFECHED  SQL_TYPE  N_FUNS  SESS_ID           MEM_ADDR
0          NULL      0             3         0       139698167141640   139698167908040
(used time: 0.760(ms))

各列即仿 Java VM 的栈式执行器内部状态:VSTACK_SIZE=1024(栈总容量,槽数)、VTOP=1022(栈顶指针槽位)、VUSED=2(已用槽数)、STKFRM_DEPTH=1(栈帧深度)、IP(当前指令指针)、N_FUNS=0(当前栈上函数数)。

第 3 步 复测一致性(24 小时后同一函数再次调用,验证计时可复现):

LOOP5M = 12500002500000   used time: 985.437(ms)
LOOP2M = 2000001000000    used time: 390.644(ms)
LOOP1M = 500000500000     used time: 195.586(ms)

体验结论:DM9 栈式虚拟机上 PL/SQL 解释循环稳定在 ~5.1M 次迭代/秒,V$VMS 视图可实时看到栈大小(VSTACK_SIZE)、栈顶/已用(VTOP/VUSED)、栈帧深度(STKFRM_DEPTH)、指令指针(IP)等 VM 内部状态——"仿 Java VM 的栈式执行器"不仅存在且可观测。。

1.3 单表多索引扫描(Multi-Index Scan)

测试目标:白皮书 4.2"单个表支持多索引哈希连接、消除回表操作"。按"建表 → 建索引 → 查 Hint → 计划对比/计时"四步实测,全部输出如下。

第 1 步 建表 + 造数(30 万行)

CREATE TABLE DM9_TEST.T_WIDE_MIDX ( ID INT, C01 INT, C02 VARCHAR(20), C03 DECIMAL(10,2), C04 DATE, C05 INT, C06 VARCHAR(20), C07 DECIMAL(10,2), C08 DATE, C09 INT, C10 VARCHAR(20) ) STORAGE(ON "TS_PERF"); INSERT INTO DM9_TEST.T_WIDE_MIDX SELECT LEVEL, MOD(LEVEL-1,10000)+1, 'NAME-'||LEVEL, ROUND(RAND(LEVEL)*1000,2), ADD_DAYS(TO_DATE('2025-01-01','YYYY-MM-DD'), MOD(LEVEL-1,1095)), MOD(LEVEL-1,200)+1, 'TXT-'||MOD(LEVEL-1,777), ROUND(RAND(LEVEL+99999)*500,2), ADD_DAYS(TO_DATE('2025-01-01','YYYY-MM-DD'), MOD(LEVEL-1,548)), MOD(LEVEL-1,200)+1, 'END-'||MOD(LEVEL-1,333) FROM DUAL CONNECT BY LEVEL<=300000; COMMIT;
used time: 641.316(ms)        (30 万行 10 列宽表装配+装载)

第 2 步 在三个谓词列上各建一个二级索引(多条件过滤查询 C05/C09/C08 三个过滤列):

CREATE INDEX IDX_MIDX_C05 ON DM9_TEST.T_WIDE_MIDX(C05); -- used time: 153.8(ms) CREATE INDEX IDX_MIDX_C08 ON DM9_TEST.T_WIDE_MIDX(C08); -- used time: 196.9(ms) CREATE INDEX IDX_MIDX_C09 ON DM9_TEST.T_WIDE_MIDX(C09); -- used time: 148.3(ms)

第 3 步 怎么查这个 Hint:DM9 的优化器 Hint 注册在动态视图 V$HINT_INI_INFO 中,按名检索:

SELECT PARA_NAME, HINT_TYPE FROM V$HINT_INI_INFO WHERE PARA_NAME LIKE 'MULTI%'; SELECT COUNT(*) HINT_TOTAL FROM V$HINT_INI_INFO;
PARA_NAME=MULTI_INDEX_SCAN  HINT_TYPE=OPT   ← 多索引扫描 Hint(类型 OPT=优化器类)
另有 MULTI_HASH_DIS_OPT / MULTI_IN_CVT_EXISTS / MULTI_UPD_OPT_FLAG / MULTI_UPD_MAX_COL_NUM 共 5 个 MULTI* Hint
HINT_TOTAL=216                              ← 全库注册 Hint 总数

第 4 步 EXPLAIN 计划对比(实际输出,同一语句有无 Hint 各一)

不带 Hint ——优化器只走 C05 一个索引,回表后对 C08/C09 逐行过滤:

EXPLAIN SELECT COUNT(*) FROM DM9_TEST.T_WIDE_MIDX WHERE C05 BETWEEN 1 AND 50 AND C09 BETWEEN 1 AND 50 AND C08 BETWEEN DATE '2025-06-01' AND DATE '2025-09-30';

1   #NSET2: [10, 1, 21]
2     #PRJT2: [10, 1, 21]; exp_num(1), is_atom(FALSE); INFO_BITS(0)
3       #AAGR2: [10, 1, 21]; grp_num(0), sfun_num(1), distinct_flag[0]; slave_empty(0)
4         #SLCT2: [10, 15, 21]; (T_WIDE_MIDX.C09 >= 1 AND T_WIDE_MIDX.C09 <= 60 AND T_WIDE_MIDX.C08 >= 2025-07-01 AND T_WIDE_MIDX.C08 <= 2025-12-31); slct_pushdown(0)
5           #BLKUP2: [10, 11250, 21]; IDX_MIDX_C05(T_WIDE_MIDX); use_clu_addr(0)   ← 回表
6             #SSEK2: [10, 11250, 21]; scan_type(ASC), IDX_MIDX_C05(T_WIDE_MIDX), scan_range[1,60], is_global(0)
Predicate Information: 4 - filter((T_WIDE_MIDX.C09 >= 1 AND ... <= 60 AND C08 BETWEEN ...))   ← 回表后逐行过滤

带 /*+ MULTI_INDEX_SCAN(1) */ —— 三个二级索引同时扫描,两次 ROWID 哈希连接合并,全程零回表:

EXPLAIN SELECT /*+ MULTI_INDEX_SCAN(1) */ COUNT(*) FROM DM9_TEST.T_WIDE_MIDX WHERE C05 BETWEEN 1 AND 50 AND C09 BETWEEN 1 AND 50 AND C08 BETWEEN DATE '2025-06-01' AND DATE '2025-09-30';

1   #NSET2: [10, 1, 57]
2     #PRJT2: [10, 1, 57]; exp_num(1), is_atom(FALSE); INFO_BITS(0)
3       #AAGR2: [10, 1, 57]; grp_num(0), sfun_num(1), distinct_flag[0]; slave_empty(0)
4         #PRJT2: [10, 11250, 57]; exp_num(0), is_atom(FALSE); INFO_BITS(0)
5           #HASH2 INNER JOIN: KEY(T_WIDE_MIDX.ROWID=T_WIDE_MIDX.ROWID) KEY_NULL_EQU(0)   ★ 第 1 次 ROWID 哈希连接
6             #HASH2 INNER JOIN: KEY(T_WIDE_MIDX.ROWID=T_WIDE_MIDX.ROWID) KEY_NULL_EQU(0)  ★ 第 2 次 ROWID 哈希连接
7               #SSEK2: IDX_MIDX_C05(T_WIDE_MIDX), scan_range[1,60]          ← 三索引同时扫描
8               #SSEK2: IDX_MIDX_C09(T_WIDE_MIDX), scan_range[1,60]
9             #SSEK2: IDX_MIDX_C08(T_WIDE_MIDX), scan_range[2025-07-01,2025-12-31]
Predicate Information: 5/6 - access(T_WIDE_MIDX.ROWID = T_WIDE_MIDX.ROWID)   ← 连接条件为 ROWID 相等

注意:无列统计信息,如果有列统计信息后 CBO 的基数估算变小 → 全扫成本占优,则会全表扫。CBO 按直方图选择率独立相乘:C05=50/200=25%、C09=25%、C08=122/548≈22.3% → 300000×25%×25%×22.3%≈ 4176 行(即下面计划中 SLCT2 的 [35, 4176, 21])。而实际命中 16699(300000×25%×22.3%——C05 与 C09 由同一表达式生成、完全相关,独立假设低估约 4 倍;)。因估算行数小,优化器对两个版本都判定"全扫聚簇索引"为成本最优,于是带 Hint 也走 CSCN2(MULTI_INDEX_SCAN(1) 只是把多索引路径纳入优化候选,是优化器类 Hint,并非强制走该路径,候选落选时不报错)。无统计数据时,估算为 25%(75000 行)量级,回表代价高,故选中索引路径。

dmdba SQL> EXPLAIN SELECT COUNT(*) FROM DM9_TEST.T_WIDE_MIDX WHERE C05 BETWEEN 1 AND 50 AND C09 BETWEEN 1 AND 50 AND C08 BETWEEN DATE '2025-06-01' AND DATE '2025-09-30'; 1 #NSET2: [35, 1, 21] 2 #PRJT2: [35, 1, 21]; exp_num(1), is_atom(FALSE); INFO_BITS(0) 3 #AAGR2: [35, 1, 21]; grp_num(0), sfun_num(1), distinct_flag[0]; slave_empty(0) 4 #SLCT2: [35, 4176, 21]; (T_WIDE_MIDX.C05 >= 1 AND T_WIDE_MIDX.C05 <= 50 AND T_WIDE_MIDX.C09 >= 1 AND T_WIDE_MIDX.C09 <= 50 AND T_WIDE_MIDX.C08 >= 2025-06-01 AND T_WIDE_MIDX.C08 <= 2025-09-30); slct_pushdown(0) 5 #CSCN2: [35, 300000, 21]; INDEX33555737(T_WIDE_MIDX); btr_scan(1); need_slct(0); prejudge_iescn(0) Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter((T_WIDE_MIDX.C05 >= 1 AND T_WIDE_MIDX.C05 <= 50 AND T_WIDE_MIDX.C09 >= 1 AND T_WIDE_MIDX.C09 <= 50 AND T_WIDE_MIDX.C08 >= 2025-06-01 AND T_WIDE_MIDX.C08 <= 2025-09-30))

image.png

第 5 步 执行计时对比(两条路径返回完全一致 COUNT(*) = 16699):

执行 无 Hint(1 索引+回表+过滤) /*+ MULTI_INDEX_SCAN(1) */ 加速比
第 1 次 103.407(ms) 17.685(ms) 5.8×
第 2 次 95.445(ms) 17.773(ms) 5.4×

小结:一条 SQL 解析后同时扫描同一张表的 3 个二级索引(3×SSEK2),用 2 次 ROWID 哈希连接(HASH2 INNER JOIN, KEY(ROWID=ROWID)) 求交集,无 BLKUP 回表、无全表扫描,多谓词过滤查询实测加速 5.4~5.8 倍。该特性由 Hint MULTI_INDEX_SCAN(1) 触发;计划对比方法:同一语句分别 EXPLAIN,看是否出现多次 SSEK2 + ROWID 哈希连接且无 BLKUP2。参数层面:本特性无对应 INI 参数、无需调整任何数据库配置——不带 Hint 时优化器默认走"单索引+回表",带上 Hint 即切换为多索引合并计划,纯语句级控制。

注意:①本文第 4/5 步的计划与 5.4~5.8× 加速来自"无列统计"初态,属真实测量;上图新表的全扫计划同样真实,两者口径不同、互为补充,本报告如实并存。MULTI_INDEX_SCAN(1) Hint 并不会强制走索引。
②如需复现多索引计划:删除 T_WIDE_MIDX 的列级统计即可(系统过程 SP_HP_TABLE_COL_STAT_DEINIT/SP_HP_COL_STAT_DEINIT 等在 SYSOBJECTS 中均已确认存在);重新收集(DBMS_STATS/DM 管理工具"收集统计信息")则回到全扫计划。
③生产建议:保留统计、以真实分布评估为准——本查询实际涉及 5.6% 行,全扫亦属合理选择。

1.4 查询内并行(Intra-Query Parallel)

测试目标:验证单条 SQL 内部多线程并行,重点实测"如何开启"与"怎么查生效"。

第 1 步 相关参数与开启方式

并行相关三个参数(V$PARAMETER 中会话生效值 VALUE 与 ini 文件值 FILE_VALUE 双列展示):

SELECT NAME, VALUE, FILE_VALUE FROM V$PARAMETER WHERE NAME IN ('MAX_PARALLEL_DEGREE','PARALLEL_POLICY','PARALLEL_THRD_TARGET'); NAME VALUE FILE_VALUE 说明 MAX_PARALLEL_DEGREE 4 4 单查询最大并行度 PARALLEL_POLICY 2 2 并行策略(2=允许自动并行;显式指定并行度时必然生效) PARALLEL_THRD_TARGET 0 0 并行线程目标数(0=跟随 MAX_PARALLEL_DEGREE) SELECT * FROM V$PARAMETER WHERE NAME='MAX_PARALLEL_DEGREE'; ID NAME TYPE VALUE SYS_VALUE FILE_VALUE DESCRIPTION DEFAULT_VALUE ISDEFAULT ----------- ------------------- ------- ----- --------- ---------- -------------------------------- ------------- ----------- 327 MAX_PARALLEL_DEGREE SESSION 4 4 4 Maximum degree of parallel query 1 0

开启并行的三个途径(本会话均实际执行验证):

  1. SQL Hint(最直接):SELECT /*+ MAX_PARALLEL_DEGREE(4) */ ... —— 本节主用方法;
  2. 全局内存参数:SP_SET_PARA_VALUE(2,'MAX_PARALLEL_DEGREE',4); —— 改全局 FILE_VALUE;
  3. 会话级参数:SF_SET_SESSION_PARA_VALUE('MAX_PARALLEL_DEGREE',4); —— 只改本会话 VALUE。

第 2 步 怎么查并行是否生效 —— 看执行计划算子

在 T_BIG(1000 万行,500 个分组)上对同一 GROUP BY 分别 EXPLAIN:

串行计划(不带 Hint):

EXPLAIN SELECT /*+ MAX_PARALLEL_DEGREE(1) */ GRP, COUNT(*), SUM(VAL) FROM DM9_TEST.T_BIG GROUP BY GRP;

1   #NSET2: [1798, 100000, 34]
2     #PRJT2: [1798, 100000, 34]; exp_num(2), is_atom(FALSE); INFO_BITS(0)
3       #HAGR2: [1798, 100000, 34]; grp_num(1), sfun_num(1), distinct_flag[0]; slave_empty(0) keys(T_BIG.GRP)
4         #CSCN2: [1118, 10000000, 34]; INDEX33555510(T_BIG); btr_scan(1); need_slct(0); prejudge_iescn(0)

并行计划(/*+ MAX_PARALLEL_DEGREE(4) */,同一 SQL):

EXPLAIN SELECT /*+ MAX_PARALLEL_DEGREE(4) */ GRP, COUNT(*), SUM(VAL) FROM DM9_TEST.T_BIG GROUP BY GRP;

1   #NSET2: [1462, 500, 34]
2     #LOCAL COLLECT: [1462, 500, 34]; op_id(2) n_grp_by (0) n_cols(0) n_keys(0) for_sync(FALSE)  --并行结果集
3       #PRJT2: [1462, 500, 34]; exp_num(3), is_atom(FALSE); INFO_BITS(0)
4         #HAGR2: [1462, 500, 34]; grp_num(1), sfun_num(2), distinct_flag[0,0]; slave_empty(0) keys(T_BIG.GRP)
5           #LOCAL DISTRIBUTE: [1462, 500, 34]; op_id(1) n_keys(0) n_grp(1) flt_only(FALSE) flt_site_data(FALSE)  n(0) fbtr_flag(FALSE) KEY(T_BIG.GRP)
6             #HAGR2: [1462, 500, 34]; grp_num(1), sfun_num(2), distinct_flag[0,0]; slave_empty(0) keys(T_BIG.GRP)
7               #CSCN2: [1118, 10000000, 34]; INDEX33555510(T_BIG); btr_scan(1); need_slct(0); prejudge_iescn(0)

判定方法:串行计划里只有 CSCN2→HAGR2 两层;并行计划里出现 #LOCAL DISTRIBUTE(按分组键 KEY(T_BIG.GRP) 把数据重分布给并行任务)与 #LOCAL COLLECT(收集各任务聚合结果) 两个算子包裹在 HAGR2 外层——EXPLAIN 中出现这对 LOCAL 算子即并行已生效,且 n_grp(1) 与 keys(T_BIG.GRP) 表明按分组键做并行聚合。

image.png

第 3 步 执行计时(两次路径返回的 500 组结果完全一致):

轮次 串行 /*+ MAX_PARALLEL_DEGREE(4) */ 并行 加速比
冷缓存(重启后首跑) 3.631 s 530.978 ms 6.8×
热缓存 第 1 轮 1.558 s 535.217 ms 2.9×
热缓存 第 2 轮 1.520 s 535.074 ms 2.8×

热缓存稳态加速 ≈2.87~2.9 倍、冷缓存首跑可达 6.8 倍。

第 4 步 自动并行(PARALLEL_POLICY=2)诚实记录

SP_SET_PARA_VALUE(2,'MAX_PARALLEL_DEGREE',1); SELECT NAME, VALUE, FILE_VALUE FROM V$PARAMETER WHERE NAME='MAX_PARALLEL_DEGREE'; EXPLAIN SELECT GRP, COUNT(*), SUM(VAL) FROM DM9_TEST.T_BIG GROUP BY GRP; SELECT GRP, COUNT(*), SUM(VAL) FROM DM9_TEST.T_BIG GROUP BY GRP;

不带 Hint、不调参数,直接跑同一条 1000 万行 GROUP BY 两轮:计划保持串行(EXPLAIN 无 LOCAL 算子),耗时 1.580/1.604 s —— 本测试负载下自动并行未介入,并行需 Hint 或参数显式触发。优化器自动并行对负载类型有
判定条件,不在本报告断言"自动并行失效",仅如实记录观察。

小结:查询内并行真实生效且方法链完整——开启途径三条(Hint/SP_SET_PARA_VALUE 全局/SF_SET_SESSION_PARA_VALUE 会话),生效判定靠 EXPLAIN 中的 #LOCAL DISTRIBUTE + #LOCAL COLLECT 算子对,热数据实测 2.87×;PARALLEL_POLICY=2 的自动并行对本次 GROUP BY 负载未介入。

1.5 查询计划缓存(Plan Cache + 智能复用)

测试目标:验证"执行计划缓存/复用"——硬解析如何被计划缓存摊薄、缓存结构长什么样、DDL 如何使缓存失效。

第 1 步 参数确认

SELECT NAME, VALUE, FILE_VALUE FROM V$PARAMETER WHERE NAME IN ('USE_PLN_POOL','CACHE_POOL_SIZE'); NAME VALUE FILE_VALUE --------------- ----- ---------- USE_PLN_POOL 1 1 (启用计划池,出厂默认) CACHE_POOL_SIZE 200 200 (计划池最大条目数,出厂默认)

第 2 步 同一语句三次执行(硬解析 → 计划复用)

SELECT /*+ MULTI_INDEX_SCAN(1) */ COUNT(*) PLAN_CACHE_DEMO FROM DM9_TEST.T_WIDE_MIDX WHERE C05 BETWEEN 1 AND 60 AND C09 BETWEEN 1 AND 60 AND C08 BETWEEN DATE '2025-07-01' AND DATE '2025-12-31';
第 1 次: PLAN_CACHE_DEMO=30196   used time: 24.997(ms)   ← 语法+语义解析、生成计划并入库、首次执行
第 2 次: PLAN_CACHE_DEMO=30196   used time: 21.392(ms)   ← 命中计划池,仅做执行
第 3 次: PLAN_CACHE_DEMO=30196   used time: 16.888(ms)   ← 计划/数据路径均热

第 3 步 计划缓存的两级结构(SQL 文本级 + 计划对象级,同 HASH_VALUE 关联):

SELECT S.CACHE_ITEM ITEM_SQL, S.HASH_VALUE HASHV, S.LEN LEN_SQL, P.CACHE_ITEM ITEM_PLN, P.MEM_SIZE, P.N_TABLE, P.N_RS_CACHED, P.RS_CAN_CACHED, P.INDEPENDENT FROM V$CACHEPLN P, V$CACHESQL S WHERE S.HASH_VALUE=P.HASH_VALUE AND P.SQLSTR LIKE '%PLAN_CACHE_DEMO%';
ITEM_SQL          HASHV       LEN_SQL  ITEM_PLN           MEM_SIZE  N_TABLE  N_RS_CACHED  RS_CAN_CACHED  INDEPENDENT
139688942975344   -717713888  259      139688942311808    89212     0        0            N              Y
139688942588416   -1062483740 91       139688943977808    89212     0        0            N              Y
139688942588744   73874184    161      139688944067320    89212     0        0            N              Y

解读:VCACHESQL(ITEMSQL)是一级缓存,VCACHESQL(ITEM_SQL)是一级缓存,VCACHEPLN(ITEM_PLN)是二级缓存——前者存 SQL 文本(SQL 列 + LEN 长度),后者存解析后的计划对象(MEM_SIZE、N_TABLE、INDEPENDENT 等属性),两者凭同一个 HASH_VALUE
配对;一条 SQL 文本可对应多条计划条目(本句 3 条,LEN=259 为主句)。另注意到 V$CACHESQL 里还可见内部生成语句(如 {INDEX $33555742 ON ... PARALLEL(1) ...} 这类系统自拼 SQL),印证计划池覆盖对象广泛。

第 4 步 DDL 触发的计划自动失效与再生成

(a) 失效:DROP INDEX DM9_TEST.IDX_MIDX_C09; 后

V$CACHEPLN 总条目: 117 → 107(一次 DROP INDEX 连带逐出 10 条相关计划,无需人工干预)

(b) 计划退级(此时即使仍带 MULTI_INDEX_SCAN Hint,因 C09 索引已不存在,优化器自动退化为单索引+回表+过滤):

4   #SLCT2: [10, 15, 21]; (T_WIDE_MIDX.C09 BETWEEN ... AND C08 BETWEEN ...); slct_pushdown(0)
5     #BLKUP2: [10, 11250, 21]; IDX_MIDX_C05(T_WIDE_MIDX); use_clu_addr(0)
6       #SSEK2: [10, 11250, 21]; scan_type(ASC), IDX_MIDX_C05(T_WIDE_MIDX), scan_range[1,60]

© 再生:CREATE INDEX DM9_TEST.IDX_MIDX_C09 ON DM9_TEST.T_WIDE_MIDX(C09) STORAGE(ON TS_PERF);(used time: 165.453(ms))后,同一语句 EXPLAIN 立即恢复 3×SSEK2 + 2×ROWID 哈希连接计划。

附注:EXPLAIN 自身生成的计划不进入共享计划池(重建索引后 V$CACHEPLN 计数未改变),真正入池的是执行时的计划——这点在观测时容易误读,如实记录。

第 5 步 其它观测视图:V$SQL_PARSE_HISTORY(SQL 解析历史)查询为 no rows——该记录开关未开启,如实记录;解析/计划/结果三级缓存各自的观测视图(V$CACHESQL/V$CACHEPLN /V$CACHERS)均存在并可查。

小结:计划缓存机制在两个层面被实证——复用层面:同一 SQL 三连跑 25.0→21.4→16.9ms(首跑含硬解析);结构层面:SQL 文本(VCACHESQL)与计划对象(VCACHESQL)与计划对象(VCACHEPLN)两级缓存以 HASH_VALUE 关联、条目属性齐全;
一致性层面:DROP INDEX 自动逐出相关计划并让优化器退级换计划,重建索引后立即恢复,全程无需重启或手工清理。

1.6 查询结果集缓存(Result Set Cache)——完整链实测

测试目标:验证"查询结果集缓存"——如何开启、如何查命中、DML 如何失效、失效后再访问是否自动回填。本小节经历"参数探究 → 重启改参数 → 强制开启 → 命中 → 失效 → 再命中"完整闭环证据。

第 1 步 参数性质探究:RS_CAN_CACHE 是静态参数(IN FILE)

SELECT NAME, TYPE, VALUE, FILE_VALUE FROM V$PARAMETER WHERE NAME IN ('RS_CAN_CACHE','RS_CACHE_MIN_TIME','RS_TUPLE_NUM_LIMIT'); NAME TYPE VALUE FILE_VALUE 说明 RS_CAN_CACHE IN FILE 2 2 结果集缓存模式(0 禁用/1允许/2 仅特殊计划),★ 静态参数,改后必须重启 RS_CACHE_MIN_TIME SYS 0 0 超过该执行时间的 SQL 才考虑缓存 RS_TUPLE_NUM_LIMIT IN FILE 2000 2000 结果集行数上限(超限不缓存)

性质实测证据(本会话真实输出):

SP_SET_PARA_VALUE(2,'RS_CAN_CACHE',1)  → V$PARAMETER: VALUE=2, SYS_VALUE=2, FILE_VALUE=1   ← 只改 ini 值,运行值不动
SF_SET_SESSION_PARA_VALUE('RS_CAN_CACHE',1)  → [-842]: Parameter is not a session-level ini parameter  ← 非会话级

结论:要让 RS_CAN_CACHE=1 生效,唯一途径是改 dm.ini 后重启实例。

第 2 步 出厂值(=2)下强制开启被拒绝(如实记录)

出厂默认 RS_CAN_CACHE=2 时,对任意计划调用存储过程强制开启结果集缓存:

DECLARE P BIGINT; H INT; BEGIN SELECT CACHE_ITEM, HASH_VALUE INTO P, H FROM V$CACHEPLN WHERE SQLSTR LIKE '%...%' FETCH FIRST 1 ROW ONLY; SP_SET_PLN_RS_CACHE(P, H, 1); END; /
[-7133]:The plan cannot cache result set        ← 模式 2 下内核直接拒绝
V$CACHEPLN 中该计划: RS_CAN_CACHED=N, RS_CAN_CACHED_IN_RULE=Y   ← 规则评估"可缓存"但最终判定被模式 2 拦下

第 3 步 修改参数 RS_CAN_CACHE 并重启实例

sed -i 's/^\(\s*RS_CAN_CACHE\s*=\) \s*[0-9]*/\1 1/' /data/DM9/dmdata/DAMENG/dm.ini grep -n '^\s*RS_CAN_CACHE' /data/DM9/dmdata/DAMENG/dm.ini # 115: RS_CAN_CACHE = 1 #Result set cache mode. 0: forbidden; 1: allowed only if the USE_PLN_POOL is non-zero /data/DM9/dmdbms/bin/DmServiceDAMENG stop # Stopping DmServiceDAMENG: [ OK ] /data/DM9/dmdbms/bin/DmServiceDAMENG start # Starting DmServiceDAMENG: [ OK ]

(dm.ini 注释原文即注明:“1: allowed only if the USE_PLN_POOL is non-zero”,本机 USE_PLN_POOL=1 满足条件)

重启后确认:V$PARAMETER: RS_CAN_CACHE TYPE=IN FILE, VALUE=1, FILE_VALUE=1。

第 4 步 基线查询(1000 万行 GROUP BY,500 组结果)

SELECT GRP, SUM(VAL) RS_TGT9 FROM DM9_TEST.T_BIG GROUP BY GRP ORDER BY GRP; 500 rows got used time: 00:00:02.999 (ms) ← 冷缓存首查 + 硬解析 2.999s

第 5 步 计划规则判定 + 存储过程强制开启

SELECT CACHE_ITEM, HASH_VALUE, RS_CAN_CACHED, RS_CAN_CACHED_IN_RULE FROM V$CACHEPLN WHERE SQLSTR LIKE '%RS_TGT9%'; CACHE_ITEM HASH_VALUE RS_CAN_CACHED RS_CAN_CACHED_IN_RULE 140006913209280 -345333099 N N 140006913119128 -1954094936 Y Y ← 模式=1 下此计划可缓存
SET SERVEROUTPUT ON; DECLARE P BIGINT; H INT; BEGIN SELECT CACHE_ITEM, HASH_VALUE INTO P, H FROM V$CACHEPLN WHERE SQLSTR LIKE '%RS_TGT9%' AND RS_CAN_CACHED='Y' FETCH FIRST 1 ROW ONLY; DBMS_OUTPUT.PUT_LINE('PLAN_ID='||P||' HASH_VALUE='||H); SP_SET_PLN_RS_CACHE(P, H, 1); END; /
PLAN_ID=140006913119128 HASH_VALUE=-1954094936
DMSQL executed successfully                    ← 强制开启成功(第三步的 -7133 消失)

第 6 步 命中证据:计时 + V$CACHERS 条目

连续再执行同一条语句三次:

SELECT GRP, SUM(VAL) RS_TGT9 FROM DM9_TEST.T_BIG GROUP BY GRP ORDER BY GRP;

第 2 次: used time: 00:00:01.512  (正常执行,并把结果集写入缓存)
第 3 次: used time: 0.202(ms)     ★ 直接命中结果集缓存(对比基线 1.5~3.0s)
SELECT COUNT(*) FROM V$CACHERS  → 1   (缓存池出现条目)

SELECT * FROM V$CACHERS;

CACHE_ITEM           PLN                  N_TABLES    TABLEID MEM_SIZE             EXEC_TIME
-------------------- -------------------- ----------- ------- -------------------- -----------
140006914162144     140006913119128      1           1032    236368               1509

CACHE_ITEM=140006914162144  PLN=140006913119128(即被强制开启的计划)
N_TABLES=1  TABLEID=1032(T_BIG)  MEM_SIZE=236368  EXEC_TIME=1509(ms)(回填那次执行耗时)

第 7 步 DML 失效 + 自动再缓存(闭环实证)

UPDATE DM9_TEST.T_BIG SET VAL=VAL+1 WHERE ID=1; COMMIT; SELECT GRP, SUM(VAL) RS_TGT9 FROM DM9_TEST.T_BIG GROUP BY GRP ORDER BY GRP; -- 再查
UPDATE: affect rows 1, used time: 414.614(ms)
再查:   used time: 00:00:01.509   ← 不再命中(结果集中 VAL 已变,缓存失效重算)
V$CACHERS 此刻 COUNT=2(旧条目失效留痕 + 本次重算回填的新条目)
之后连续两查: 0.300(ms)、0.174(ms)   ← 新结果集已重新缓存,恢复命中
数据正确性: GRP=1 求和 10021252174.28 → 10021252175.28,恰为 UPDATE 的 +1 ✓

小结:结果集缓存"强制开启 → 命中 → DML 失效 → 自动再缓存"闭环被完整实证,命中耗时约 0.17~0.30ms(对比全量重算 1.5~3.0s),V$CACHERS 可逐条查到缓存所属计划(PLN)、基表(TABLEID)、内存占用(MEM_SIZE)与回填耗时(EXEC_TIME)。
两点如实说明:(1) RS_CAN_CACHE 是 IN FILE 静态参数——运行期 SP_SET_PARA_VALUE 与 SF_SET_SESSION_PARA_VALUE 均无法改变运行值,必须改 dm.ini 并重启;
(2) 出厂模式 2 下内核拒绝强制开启(-7133),且本次测试负载未观测到全自动填充(无任何配置时 N_RS_CACHED 恒为 0),缓存由存储过程显式指定计划后生效。


2. AI 原生与智能化 —— 重点体验

2.1 原生向量类型 VECTOR

SQL:

ALTER USER "DM9_TEST" QUOTA UNLIMITED ON "TS_AI"; SP_SET_PARA_VALUE(2,'VECTOR_INDEX_BUILD_PARALLEL_DEGREE',0); SELECT 'para' LBL, PARA_NAME, PARA_VALUE FROM V$DM_INI WHERE PARA_NAME IN ('VECTOR_INDEX_BUILD_PARALLEL_DEGREE','HNSW_SHARD_SEARCH_PARALLEL_DEGREE'); CREATE TABLE DM9_TEST.T_VEC_BIG( ID INT, TITLE VARCHAR(64), CATEGORY_ID INT, PRICE DECIMAL(10,2), VEC VECTOR(16, FLOAT32) ) STORAGE(ON "TS_AI"); INSERT INTO DM9_TEST.T_VEC_BIG (ID, ITEM_NAME, CAT_ID, PRICE, VEC) SELECT LEVEL, CONCAT('ITEM-', LEVEL), MOD(LEVEL-1,20)+1, ROUND(RAND(LEVEL+30000000)*200,2), TO_VECTOR('['||ROUND(RAND(LEVEL+17),3)||','||ROUND(RAND(LEVEL+1000017),3)||','||ROUND(RAND(LEVEL+2000017),3)||','||ROUND(RAND(LEVEL+3000017),3)||','||ROUND(RAND(LEVEL+4000017),3)||','||ROUND(RAND(LEVEL+5000017),3)||','||ROUND(RAND(LEVEL+6000017),3)||','||ROUND(RAND(LEVEL+7000017),3)||','||ROUND(RAND(LEVEL+8000017),3)||','||ROUND(RAND(LEVEL+9000017),3)||','||ROUND(RAND(LEVEL+10000017),3)||','||ROUND(RAND(LEVEL+11000017),3)||','||ROUND(RAND(LEVEL+12000017),3)||','||ROUND(RAND(LEVEL+13000017),3)||','||ROUND(RAND(LEVEL+14000017),3)||','||ROUND(RAND(LEVEL+15000017),3)||']', 16, FLOAT32, DENSE) FROM DUAL CONNECT BY LEVEL <= 500000; COMMIT; SELECT COUNT(*) FROM DM9_TEST.T_VEC_BIG; --INSERT: affect rows 500000, used time: 00:00:06.709 (1702) -- 6.7 秒装载 50 万个 16 维向量

支持稠密/稀疏两种形态(VECTOR(64, FLOAT32, SPARSE) 稀疏表 T_SPARSE_VEC 建表成功),支持 DENSE/SPARSE 间 CAST 互转;限制:向量列不可做主键/唯一键、只允许建向量索引、HUGE 表不支持向量类型。

2.2 向量函数与运算符全集

SQL:

SELECT NAME FROM V$IFUN WHERE NAME LIKE '%VECTOR%' ORDER BY NAME; SELECT TO_VECTOR('[1,2,3,4]',4,FLOAT32) <-> TO_VECTOR('[1,2,3,5]',4,FLOAT32) OP_L2, -- 欧式距离 TO_VECTOR('[1,2,3,4]',4,FLOAT32) <+> TO_VECTOR('[1,2,3,5]',4,FLOAT32) OP_L1, -- 曼哈顿 TO_VECTOR('[1,2,3,4]',4,FLOAT32) <=> TO_VECTOR('[4,3,2,1]',4,FLOAT32) OP_COS, -- 余弦距离 FROM_VECTOR(TO_VECTOR('[1,2,3,4]',4,FLOAT32)) BACK_TO_STR;

image.png

执行结果:

V$IFUN 向量函数清单(15 个): TO_VECTOR, FROM_VECTOR, VECTOR_DISTANCE, VECTOR_DIMS,
  VECTOR_NORM, VECTOR_NORMALIZATION, VECTOR_SERIALIZE, VECTOR_DIMENSION_COUNT,
  VECTOR_DIMENSION_FORMAT, SP_REBUILD_VECTOR_HNSW_INDEX / IVFFLAT / DISKANN / BMP_INDEX ...

OP_L2=1.0000000E+00  OP_L1=1.00000000E+00  OP_COS=3.33333E-01  BACK_TO_STR=[1E+000,2E+000,3E+000,4E+000]

体验发现的语法要点:VECTOR_DISTANCE(vec, v, cosine) 的距离度量参数必须裸写(cosine/euclidean/dot…),带引号 'cosine' 会报 [-2007] 语法错且报错位置有误导性。

2.3 精确 kNN 相似查询

SQL:

SELECT ID FROM DM9_TEST.T_VEC_BIG ORDER BY VECTOR_DISTANCE(VEC, TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH FIRST 10 ROWS ONLY;

执行结果(50 万行):

返回 10 行(ID: 235683,133312,320513,...)  used time: 92.244(ms)
执行计划: #CSCN2 全表扫描 500000 行 + #SORT3 top-N 排序(与预期一致:精确查询全量计算距离)

2.4 向量索引:HNSW/IVFFLAT/BMP/DISKANN 创建实测

创建向量表 SQL:

CREATE TABLE DM9_TEST.T_VEC_BIG_IVF LIKE DM9_TEST.T_VEC_BIG;
INSERT INTO DM9_TEST.T_VEC_BIG_IVF SELECT * FROM DM9_TEST.T_VEC_BIG;
COMMIT;

CREATE TABLE DM9_TEST.T_SPARSE_VEC(ID INT, VEC VECTOR(64, FLOAT32, SPARSE)) STORAGE(ON "TS_AI");
INSERT INTO DM9_TEST.T_SPARSE_VEC
SELECT LEVEL,
  TO_VECTOR('[64,['||(MOD(LEVEL-1,56)+1)||','||(MOD(LEVEL-1,56)+2)||','||(MOD(LEVEL-1,56)+3)||','||(MOD(LEVEL-1,56)+4)||'],['||ROUND(RAND(LEVEL),3)||','||ROUND(RAND(LEVEL+1000000),3)||','||ROUND(RAND(LEVEL+2000000),3)||',
'||ROUND(RAND(LEVEL+3000000),3)||']]',64,FLOAT32,SPARSE)
FROM DUAL CONNECT BY LEVEL<=2000;
COMMIT;

CREATE TABLE DM9_TEST.T_DISK_PROBE(ID INT, VEC VECTOR(8, FLOAT32)) STORAGE(ON "TS_AI");
INSERT INTO DM9_TEST.T_DISK_PROBE SELECT LEVEL, '['||ROUND(RAND(LEVEL),3)||','||ROUND(RAND(LEVEL+1000),3)||','||ROUND(RAND(LEVEL+2000),3)||','||ROUND(RAND(LEVEL+3000),3)||','||ROUND(RAND(LEVEL+4000),3)||','||ROUND(RAND(LEVEL+5000),3)||','||ROUND(RAND(LEVEL+6000),3)||','||ROUND(RAND(LEVEL+7000),3)||']' FROM DUAL CONNECT BY LEVEL<=1000;
COMMIT;

创建向量索引 SQL:

CREATE VECTOR INDEX IDX_VEC_BIG_HNSW ON DM9_TEST.T_VEC_BIG(VEC) ORGANIZATION NEIGHBOR GRAPH DISTANCE COSINE WITH TARGET ACCURACY 95 PARAMETERS(TYPE HNSW, NEIGHBOR 16, EFCONSTRUCTION 64); CREATE VECTOR INDEX IDX_VEC_BIG_IVF ON DM9_TEST.T_VEC_BIG_IVF(VEC) ORGANIZATION NEIGHBOR PARTITIONS DISTANCE COSINE WITH TARGET ACCURACY 90 PARAMETERS(TYPE IVF, NEIGHBOR PARTITIONS 128); CREATE VECTOR INDEX IDX_SPARSE_BMP ON DM9_TEST.T_SPARSE_VEC(VEC) ORGANIZATION NEIGHBOR PARTITIONS BITMAP WITH DISTANCE COSINE PARAMETERS(TYPE BMP, BLOCK 100); CREATE VECTOR INDEX IDX_DISK_PROBE ON DM9_TEST.T_DISK_PROBE(VEC) ORGANIZATION NEIGHBOR GRAPH DISTANCE COSINE PARAMETERS(TYPE DISKANN);

执行结果(建索引耗时对比):

索引 数据规模 建索引耗时 INDEX_TYPE(DBA_INDEXES 实测)
HNSW 50 万×16 维 00:01:40.592 VECTOR HNSW
HNSW 5 万×16 维 22.782 s VECTOR HNSW
IVFFLAT 50 万×16 维(128 聚类中心) 1.840 s VECTOR IVFFLAT
IVFFLAT 5 万×16 维(64 中心) 324.631 ms VECTOR IVFFLAT
BMP(稀疏) 2000×64 维 26.501 ms VECTOR BMP
DISKANN 1000×8 维 121.430 ms VECTOR DISKANN

体验发现:官方宣传 DISKANN 但官方 未公开其建索引语法;实测 PARAMETERS(TYPE DISKANN) 在 NEIGHBOR GRAPH 组织下即可创建成功,DBA_INDEXES 认作 VECTOR DISKANN,V$IFUN 中亦存在 SP_REBUILD_VECTOR_DISKANN_INDEX 重建函数。另一实测限制:一条向量列只允许建一个向量索引(报 [-3236] such column list already indexed),故 IVF 对比使用了复制表。IVFFLAT 建索引极快(毫秒~秒级),HNSW 较慢但查询精度更高——与理论一致。

2.5 近似查询(ANN)性能与召回率 —— 精确 vs 近似的量化对比

SQL:

-- 近似(ANN)语法: FETCH APPROX FIRST n ROWS ONLY [WITH TARGET ACCURACY p] SELECT ID FROM DM9_TEST.T_VEC_BIG ORDER BY VECTOR_DISTANCE(VEC, TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH APPROX FIRST 10 ROWS ONLY WITH TARGET ACCURACY 90; -- 召回率交叉验证(精确 top10 与近似 top10 的交集数) WITH EXACT AS (SELECT ID FROM DM9_TEST.T_VEC_BIG ORDER BY VECTOR_DISTANCE(VEC,TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH FIRST 10 ROWS ONLY),APPROX AS (SELECT ID FROM DM9_TEST.T_VEC_BIG ORDER BY VECTOR_DISTANCE(VEC,TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH APPROX FIRST 10 ROWS ONLY WITH TARGET ACCURACY 90) SELECT (SELECT COUNT(*) FROM EXACT X JOIN APPROX A ON X.ID=A.ID) HNSW90_RECALL FROM DUAL;

执行结果(50 万行 × 16 维,同一查询向量,逐条计时):

查询方式 耗时 召回率(top10 vs 精确结果)
精确 kNN(全扫) 92.244 ms 基准
ANN-HNSW WITH TARGET ACCURACY 90 39.610 ms(2.3×提速) 10/10
ANN-HNSW WITH TARGET ACCURACY 99 37.926 ms 10/10
ANN-HNSW(缺省精度) 30.818 ms 10/10
ANN-IVFFLAT ACCURACY 90 15.883 ms(5.8×提速) 10/10
ANN-IVFFLAT ACCURACY 99 13.009 ms 10/10
ANN-HNSW k=1000 0.865 ms(返回 1000 行) —

在 5 万行规模(T_VEC_HNSW)上:精确 9.8ms / ANN 6.4ms,top-3 完全一致。

结论:ANN 查询在 50 万向量上提速 2~6 倍且召回率 100%(本次数据分布下 ANN 与精确结果完全一致);IVFFLAT 在当前参数下比 HNSW 更快(128 聚类中心 + 热点数据集);指南中"欧式距离查询不使用索引、单行向量查询不回表索引、HNSW k≥1000 不索引/IVF 探测超聚类数不索引"等退化为精确/异常回退规则在本次 k=1000 场景未触发(正常返回)。

2.6 执行计划中的向量算子 VSEK

EXPLAIN(HNSW,实际输出):

EXPLAIN SELECT ID FROM DM9_TEST.T_VEC_BIG ORDER BY VECTOR_DISTANCE(VEC, TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH APPROX FIRST 10 ROWS ONLY WITH TARGET ACCURACY 90;

1   #NSET2: [1, 10, 64]
2     #PRJT2: [1, 10, 64]
3       #SORT3: top_flag(1)                          -- 对候选 top-10
4         #PRJT2: [1, 19200, 64]                     -- 候选集 19200 行(=ef_search 相关)
5           #BLKUP2: IDX_VEC_BIG_HNSW(T_VEC_BIG)
6             #VSEK: IDX_VEC_BIG_HNSW(T_VEC_BIG), type(HNSW), ef_search(64)

EXPLAIN SELECT ID FROM DM9_TEST.T_DISK_PROBE ORDER BY VECTOR_DISTANCE(VEC, TO_VECTOR('[0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5]',8,FLOAT32),cosine) FETCH APPROX FIRST 3 ROWS ONLY WITH TARGET ACCURACY 90;

DISKANN 表同样出 #VSEK: ..., type(DISKANN), ef_search(32)——向量索引搜索以专用算子 VSEK 呈现,可与哈希连接(混合查询)自由组合。

image.png

2.7 向量+关系混合查询(多模融合)

SQL:

CREATE TABLE DM9_TEST.T_ITEM_CAT(CATEGORY_ID INT PRIMARY KEY, CAT_NAME VARCHAR(40)); INSERT INTO DM9_TEST.T_ITEM_CAT SELECT LEVEL, CONCAT('CATEGORY-', LEVEL) FROM DUAL CONNECT BY LEVEL<=20; SELECT v.ID, v.TITLE, v.PRICE, c.CAT_NAME FROM DM9_TEST.T_VEC_BIG v JOIN DM9_TEST.T_ITEM_CAT c ON v.CATEGORY_ID=c.CATEGORY_ID WHERE v.CATEGORY_ID IN (5,12) ORDER BY VECTOR_DISTANCE(v.VEC, TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH APPROX FIRST 5 ROWS ONLY WITH TARGET ACCURACY 90;

执行结果:

1  ITEM-133312  31.91   CATEGORY-12
2  ITEM-392645  160.86  CATEGORY-5
3  ITEM-374012  145.33  CATEGORY-12
4  ITEM-466685  165.26  CATEGORY-5
5  ITEM-357832  131.91  CATEGORY-12
used time: 37.808(ms)

执行计划: #VSEK(type HNSW) + #HASH2 INNER JOIN(类别表) + #SSEK2(类别主键)
          + #HASH RIGHT SEMI JOIN(IN 过滤) —— 向量近似检索与关系 Join/过滤在同一计划融合执行

“以向量搜相似”(查询向量取自表中一行):

SELECT ID, TITLE FROM DM9_TEST.T_VEC_BIG WHERE ID<>25000 ORDER BY VECTOR_DISTANCE(VEC, (SELECT VEC FROM DM9_TEST.T_VEC_BIG WHERE ID=25000), cosine) FETCH FIRST 5 ROWS ONLY; -- 返回与 ITEM-25000 最相似的 5 件商品(ID: 381682,283936,348355,465814,344692),164.158 ms

image.png

2.8 向量索引构建/查询并行参数

  • VECTOR_INDEX_BUILD_PARALLEL_DEGREE=4(出厂已设置):HNSW 50 万向量建索引在 100.6 秒完成,即为并行构建的效果。
  • HNSW_SHARD_SEARCH_PARALLEL_DEGREE:会话级调至 4/8 后 ANN 查询 38.7ms → 33.5ms,50 万规模下有温和提升(记录如实:本规模提升不显著)。

2.9 问题记录

初测时:把 HNSW_SHARD_SEARCH_PARALLEL_DEGREE 经 SP_SET_PARA_VALUE(2,'HNSW_SHARD_SEARCH_PARALLEL_DEGREE',8) 调至 4、8,50 万 HNSW ANN 计时 38.726ms(=4)→ 33.462ms(=8),提升温和(该规模下不明显)。

复测时发现严重问题:SP_SET_PARA_VALUE(2,‘HNSW_SHARD_SEARCH_PARALLEL_DEGREE’,8) 会把这些值持久化写入 dm.ini。实例重启后(ini 的 8 生效),对 50 万行 HNSW 表执行 ANN 查询(accuracy 90)导致实例 SIGSEGV 崩溃,三次独立触发、三次全崩:

SERVER LOG 实测(/data/DM9/dmdbms/log/dm_DMSERVER_202609.log):
2026-09-23 10:50:05.961 [FATAL] database P0002205860 ... sigterm_handler receive signal 11
2026-09-23 10:58:51.340 [FATAL] database P0002548388 ... sigterm_handler receive signal 11
2026-09-23 10:58:51.340 [FATAL] database P0002548388 ... [for dem]SYSTEM SHUTDOWN ABORT.
                           ↑ 客户端侧对应现象:DISQL-10036: connection lost(连接被重置,实例进程崩溃)

崩溃排除过程(逐步执行):

  1. 现象定位:SELECT ID FROM T_VEC_BIG ORDER BY VECTOR_DISTANCE(...) FETCH APPROX FIRST 10 ROWS ONLY WITH TARGET ACCURACY 90; 执行即断连,端口 15236 无响应([-70028]:Create SOCKET connection failure.——实例已死);
  2. 恢复:DmServiceDAMENG restart(stop+start 均 [OK]),随后查 dm.ini 发现 HNSW_SHARD_SEARCH_PARALLEL_DEGREE = 8 残留在文件中;
  3. 对照验证 A(=1):SP_SET_PARA_VALUE(1,'HNSW_SHARD_SEARCH_PARALLEL_DEGREE',1); 后同一 ANN 查询正常,实测 1.210s(冷)→ 40.456ms(热),稳定复跑 3 次无异常;
  4. 对照验证 B(=8):再次改回 8 后同一查询再次崩溃(connection lost,第三次复现);
  5. 修复:重启实例 → SP_SET_PARA_VALUE(1,'HNSW_SHARD_SEARCH_PARALLEL_DEGREE',1) + sed -i 把 dm.ini 文件中的 8 改回 1 → 重启验证,运行时与文件均为 1,ANN 查询 40.5ms 量级稳定。

结论:HNSW_SHARD_SEARCH_PARALLEL_DEGREE=8 与 50 万级 HNSW ANN 查询在该开发版上组合存在可复现的段错误崩溃;奔溃原因不得而知,没有任何官方文档,资料太少了,暂时只能这样了。

本着严谨的态度又找了一套从 DM8 升级上来的库测试了一遍,确实只要创建下面的索引,并行开到 8,ANN 查询就会导致数据库崩溃。 但只要删除索引,查询就没有问题。

SQL> CREATE VECTOR INDEX IDX_VEC_BIG_HNSW ON DM9_TEST.T_VEC_BIG(VEC) 2 ORGANIZATION NEIGHBOR GRAPH DISTANCE COSINE 3 WITH TARGET ACCURACY 95 4 PARAMETERS(TYPE HNSW, NEIGHBOR 16, EFCONSTRUCTION 64); 操作已执行 已用时间: 00:08:29.207. 执行号:639. SQL> drop index DM9_TEST.IDX_VEC_BIG_HNSW; 操作已执行 已用时间: 66.068(毫秒). 执行号:601. SQL> SQL> SELECT ID FROM DM9_TEST.T_VEC_BIG ORDER BY VECTOR_DISTANCE(VEC, TO_VECTOR('[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.85,0.75 ,0.65,0.55,0.45,0.35]',16,FLOAT32),cosine) FETCH APPROX FIRST 10 ROWS ONLY WITH TARGET ACCURACY 90; 行号 ID ---------- ----------- 1 235683 2 133312 3 320513 4 334146 5 140914 6 46003 7 138002 8 293210 9 115778 10 82795 10 rows got 已用时间: 226.045(毫秒). 执行号:602. SQL>

图片.png


3. 其他单机可体验特性

3.1 JSON 多模型(JSON/JSONB 文档类型)

SQL:

CREATE TABLE DM9_TEST.T_JSON_DOC(ID INT PRIMARY KEY, DOC JSON, DOCB JSONB) STORAGE(ON "TS_AI"); INSERT INTO DM9_TEST.T_JSON_DOC VALUES(1, '{"order_id":10001,"customer":{"name":"张三","vip_level":3}, "items":[{"sku":"A001","qty":2,"price":99.5},{"sku":"B002","qty":1,"price":199.0}], "tags":["new","2026-09-22"],"total":398.0}', ...); SELECT ID, JSON_VALUE(DOC, '$.customer.vip_level') VIP FROM DM9_TEST.T_JSON_DOC; -- 1:3 2:5 SELECT ID FROM DM9_TEST.T_JSON_DOC WHERE JSON_EXISTS(DOC, '$.items[*]?(@.price > 100)'); -- 仅 1 SELECT ID, JSON_QUERY(DOCB, '$.readings') READINGS FROM DM9_TEST.T_JSON_DOC; -- [23.5,24.1,23.8] SELECT ID, jt.SKU, jt.QTY, jt.PRICE FROM DM9_TEST.T_JSON_DOC, JSON_TABLE(DOC, '$.items[*]' COLUMNS(SKU VARCHAR(20) PATH '$.sku', QTY INT PATH '$.qty', PRICE DECIMAL(8,2) PATH '$.price')) jt; -- 3 行展开 SELECT JSON_OBJECT('id' VALUE 1,'name' VALUE '达梦') OBJ, JSON_ARRAY(1,'DM9') ARR FROM DUAL;

执行结果: 全部成功JSON_OBJECT={"id":1,"name":"达梦"})。库内注册 JSON* 函数 19 个(V$IFUN 计数)。JSON_MODE=0(Oracle 兼容模式)。

模式相关行为(实测):运算符 ->/->>/–/|| 仅在 JSON_MODE=1(PG)/2(MySQL) 下可用(指南明文),本环境 JSON_MODE=0 下使用报错,Oracle 风格建议用 JSON_VALUE/QUERY/EXISTS——这是重要的兼容性细节。

多模融合实测(向量↔JSON 双向互转):

SELECT CAST(TO_VECTOR('[1,2,3]',3,FLOAT32) AS JSONB) VEC2JSONB FROM DUAL; -- [1E+000,2E+000,3E+000] ✓ SELECT CAST(CAST('[1.5,2.5,3.5]' AS JSONB) AS VECTOR(3, FLOAT32)) JSONB2VEC FROM DUAL; -- [1.5E+000,...] ✓ SELECT TO_JSON(TO_VECTOR('[1,2,3,4]',4,FLOAT32)) VEC2JSONFUNC FROM DUAL; -- ✓ -- TO_VECTOR(TO_JSON(...)) 报 [-14304](TO_JSON 返回 JSON 类型而非字符串),如实记录

3.2 高安全特性(三权/四权分立、审计、加密、脱敏)

(a) 三权账户状态(实测):

SELECT USERNAME, ACCOUNT_STATUS FROM DBA_USERS WHERE USERNAME IN ('SYSDBA','SYSAUDITOR','SYSSSO','SYSDBO'); -- SYSDBA OPEN / SYSAUDITOR OPEN / SYSSSO EXPIRED(本环境第四个 SYSDBO 不存在)

(b) 权限隔离——三次越权尝试全部被内核拒绝(三权分立直观证据):

测试 语句 结果
DBA 越权审计 SP_AUDIT_STMT('UPDATE TABLE','DM9_TEST','ALL')(SYSDBA 执行) [-5578] No audit privilege
DBA 越权改安全员 ALTER USER SYSAUDITOR IDENTIFIED BY ...(SYSDBA 执行) [-5549] No alter user privilege
DBA 越权读审计记录 SELECT COUNT(*) FROM V$AUDITRECORDS(SYSDBA 执行) [-5504] No select privilege on object [SYSAUDITOR.V$AUDITRECORDS]

审计员账户(SYSAUDITOR)初始口令为本环境初始化时设置(默认口令尝试失败;SYSSSO 未激活 EXPIRED),故未能完成"启用审计规则→产生审计记录→安全员查询记录"全链路实测;但 VIFUN中确认存在完整审计体系(SPAUDITSTMT、SPAUDITOBJECT、SPAUDITSQLSEQ∗、SPAUDITSETENC等8个过程),VIFUN 中确认存在完整审计体系(SP_AUDIT_STMT、SP_AUDIT_ OBJECT、SP_AUDIT_SQLSEQ_*、SP_AUDIT_SET_ENC 等 8 个过程),VAUDITRECORDS 归属 SYSAUDITOR。三权分立的"权限对抗"部分在 (b) 中得到强实证。

© 透明列加密(实测全链路):

CREATE TABLE DM9_TEST.T_SECRET( ID INT, CARD_NO VARCHAR(30) ENCRYPT, -- 默认算法加密列 AMOUNT DECIMAL(12,2) ENCRYPT WITH DES_ECB -- 指定 DES_ECB 算法 ) STORAGE(ON "TS_AI"); INSERT INTO DM9_TEST.T_SECRET SELECT LEVEL, '62220000'||(10000000+LEVEL), ROUND(RAND(LEVEL)*50000,2) FROM DUAL CONNECT BY LEVEL<=100; -- affect rows 100 SELECT * FROM DM9_TEST.T_SECRET WHERE ID IN (1,2,50); -- 透明解密:明文可见 -- 1 | 6222000010000001 | 39394.04 ...

应用无感透明加解密:写入自动加密、查询自动解密——"落盘数据加密"能力实测成立(列级;全库透明加密需初始化阶段配置,本环境已安装未覆盖)。

(d) 动态脱敏:V$IFUN 中无 MASK 类内置函数(COUNT(*)=0),脱敏能力以策略/工具形态提供,单机 disql 无法直接体验——如实记录。

3.3 Oracle 兼容(COMPATIBLE_MODE=0)

SQL 与执行结果(全部成功):

特性 实测语句 结果
DUAL/SYSDATE SELECT 1+1 CALC, SYSDATE NOW, USER CUR_USER FROM DUAL 2 / 2026-09-22 15:58:16 / SYSDBA
ROWNUM top-n SELECT ROWNUM RN, ... FROM (SELECT ... ORDER BY AMOUNT DESC) WHERE ROWNUM<=5 5 行
DECODE/NVL/NULLIF DECODE(MOD(ID,3),0,'再次购买',1,'首购','其他') 中文标签正确
外连接 (+) WHERE V.CATEGORY_ID=C.CATEGORY_ID(+) 语法通过
PL/SQL 包 CREATE OR REPLACE PACKAGE PKG_ORA(F_ADD/P_HELLO) + CALL P_HELLO('达梦用户') HELLO, 达梦用户 FROM DM9 PL/SQL (Oracle-compatible package)
包函数 SELECT PKG_ORA.F_ADD(39,3) FROM DUAL 42
%TYPE/%ROWTYPE 匿名块 DECLARE T_SALES.AMOUNT%TYPE、T_SALES%ROWTYPE 成功
关联数组 TYPE T_IDS IS TABLE OF INT INDEX BY INT + COUNT 2
CONNECT BY 本文所有造数语句 全部成功

3.4 无锁热备(在线备份不影响业务,实测并发证据)

并发实测设计: 后台启动全库备份,2 秒后前台并发执行 20 万行 INSERT,比较时间重叠。

SQL:

BACKUP DATABASE FULL BACKUPSET '/data/DM9/dmdata/bak/db_full_0922'; -- 后台会话 INSERT INTO DM9_TEST.T_SALES SELECT ... FROM DUAL CONNECT BY LEVEL<=200000; -- 前台会话 COMMIT;

执行结果(时间线实测):

时刻 T+0s    BACKUP 开始
时刻 T+2s    INSERT 开始(备份进行中)
时刻 T+5.7s  INSERT 完成: affect rows 200000, used time: 00:00:03.674   ← 无等待、无阻塞
时刻 T+6.7s  BACKUP 完成: executed successfully, used time: 00:00:06.748
备份产物: /data/DM9/dmdata/bak/db_full_0922/(目录已生成)

结论:20 万行写入全程落入备份执行窗口内且零阻塞——"无锁热备"直接实证。备份期间数据库保持 OPEN,业务读写正常。

3.5 闪回(Flashback:LSN 级 + 回收站 DROP 恢复)

(a) LSN 闪回(删除恢复):

ALTER SYSTEM SET 'ENABLE_FLASHBACK'=1; -- DMSQL executed successfully(动态生效) CREATE TABLE DM9_TEST.T_FLASH_TEST(ID INT, NOTE VARCHAR(20)) STORAGE(ON "TS_AI"); INSERT INTO DM9_TEST.T_FLASH_TEST SELECT LEVEL,'ROW-'||LEVEL FROM DUAL CONNECT BY LEVEL<=5; COMMIT; -- CUR_LSN=2202058(select CUR_LSN from V$RLOG 查得) DELETE FROM DM9_TEST.T_FLASH_TEST WHERE ID<=2; COMMIT; SELECT COUNT(*) FROM DM9_TEST.T_FLASH_TEST; -- 3 行(AFTER_DEL) FLASHBACK TABLE DM9_TEST.T_FLASH_TEST TO LSN 2202058; SELECT COUNT(*) FROM DM9_TEST.T_FLASH_TEST; -- 5 行(AFTER_FLASHBACK)

(b) 回收站闪回(误 DROP 恢复):

-- RECYCLEBIN 为静态参数,改 dm.ini=2 并重启实例后生效 DROP TABLE DM9_TEST.T_FLASH_TEST; -- executed successfully FLASHBACK TABLE DM9_TEST.T_FLASH_TEST TO BEFORE DROP; SELECT COUNT(*) FROM DM9_TEST.T_FLASH_TEST; -- 5 行(AFTER_BEFORE_DROP) SELECT * FROM DM9_TEST.T_FLASH_TEST ORDER BY ID; -- ROW-1..ROW-5 完整恢复

首次 BEFORE DROP 失败报 [-9805] Recycle bin not enabled... → 定位 INI RECYCLEBIN(0=关/1=DROP 进回收站/2=DROP+TRUNCATE),改 2 重启后成功。这如实展示了 DM9 回收站参数的语义层级。


4. 体验结论与建议

4.1 亮点(本次实测确认)

  1. 批量装载:百万行 950ms(105 万行/秒),工程调优价值极大。
  2. 单表多索引扫描:3 索引 + ROWID 哈希双连接 + 零回表,多谓词 OLTP 查询利器(初态实测加速 5.4~5.8×;对统计信息敏感、Hint 非强制)。
  3. 查询内并行:热数据 2.87×、冷数据 6.8× 加速,开启路径三条(Hint/全局/会话)与 EXPLAIN 判定法全部实证。
  4. 栈式虚拟机:~510 万次迭代/秒的 PL/SQL 解释性能,V$VMS 提供堆栈级可观测性。
  5. 向量能力完整:VECTOR 类型、4 类索引(HNSW/IVFFLAT/BMP/DISKANN 全实例化)、精确/近似查询语法一体化、VSEK 算子可 EXPLAIN、召回率 100%(10/10)、混合查询与关系引擎无缝融合。
  6. 向量装载/建索引性能:50 万向量 6.7s;IVFFLAT 秒级建索引、DISKANN 121ms 建成——规模化 AI 应用可用性高。
  7. 多模型融合:向量↔JSON 双向转换、JSON_TABLE 行化、JSON_VALUE/EXISTS/QUERY 完备。
  8. 安全分权被内核强执行:三次越权均被拒绝且错误码精确(-5578/-5549/-5504)。
  9. 无锁热备:备份与写入并发零阻塞(时间线证据);LSN 闪回与回收站 DROP 恢复两模式可用。
  10. 故障可诊断性:测试期间把实例"打崩"(SIGSEGV/connection lost)后,DmServiceDAMENG restart + 日志取证(dm_DMSERVER 日志 FATAL 行带信号码与线程号)定位到参数根因并完成闭环修复——崩溃恢复路径可用、问题可归因可回退。

4.2 发现的坑与限制

  1. 向量距离度量参数必须裸写且仅支持 cosine/dot/euclidean 三种字面量:'cosine'(带引号)→ [-2007] 语法错(报错位置有误导性);l2/l1/euclid/manhat 字面量不存在 → [-14322](欧式距离字面量为 euclidean,曼哈顿须用运算符 <+>)。官方未说明,建议明示全部合法字面量清单。
  2. 一个向量列只允许一个向量索引;对比测试需复制表。
  3. DISKANN 索引官方手册无语法(实测 TYPE DISKANN 可用),建议文档补齐。
  4. 结果集缓存:规则判定视图存在(RS_CAN_CACHED_IN_RULE),但 RS_CAN_CACHE 是静态参数(IN FILE),运行期改不了、必须改 dm.ini 重启;出厂模式 2 下强制开启被内核拒绝(-7133);模式 1 下 SP_SET_PLN_RS_CACHE 强制链路完整成功(命中 0.17~0.30ms vs 重算 1.5~3.0s);全自动填充本次负载未观测到——建议官方给出自动缓存生效条件清单与静态参数的在线生效途径。
  5. JSON ->/->> 等运算符与 JSON_MODE 绑定,Oracle 兼容模式(默认)下不可用,迁移 Oracle 应用需注意。
  6. SYSSSO 初始未激活(EXPIRED)且 SYSDBA 无权激活/改密——开箱默认部署需在初始化向导中完成三权口令规划。
  7. # 字符不能出现在 disql 口令中(与扩展选项冲突)。
  8. ALTER SYSTEM SET 'ENABLE_FLASHBACK'=1 会话期生效、重启失效(未落 ini),生产固化需改 dm.ini。
  9. 【重要,实测崩溃】HNSW_SHARD_SEARCH_PARALLEL_DEGREE=8 与 50 万级 HNSW ANN 查询组合在本开发版(build 2026-04-17)上导致实例 SIGSEGV 崩溃(服务端日志 signal 11/SYSTEM SHUTDOWN ABORT),三次独立触发三次全崩;=1 时同查询稳定 40ms 量级、=4/8 对小表无害。大索引上的分片并行度需做充分稳定性验证后方可上线(详见 2.8 完整排查记录)。
  10. SP_SET_PARA_VALUE(2,...)(全局 scope)会把参数值持久化写入 dm.ini 文件——参数实验若不回退,实例重启后仍生效(本次即因此遗留 8 并触发第 9 条崩溃);实验型调参务必"改前记录原值、改后立即回退",dm.ini 手动修改也要留备份。
  11. MULTI_INDEX_SCAN(1) Hint 是"启用候选"而非"强制路径":当列级直方图统计齐备、CBO 估算命中行数小(如 4176/300000)时,带 Hint 依然走全表扫描且无任何提示;同一语句在无统计初态下则稳定产出 3×SSEK2 计划。读"Hint 生效"类结论时必须注明当时的统计信息状态。

注:文中测试仅供参考,因为 dm9 官方文档没有公布,这也不是企业版,可能功能不是十分全面,测试也不一定十分正确全面,仅供参考。转载请注明来源 JiekeXu DBA之路。文中部分内容来源于网络资料或 AI,如有侵权,请私信联系我删除,谢谢。

全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~

欢迎关注我的公众号【JiekeXu DBA之路】,一起学习新知识!
——————————————————————————
公众号:JiekeXu DBA之路
墨天轮:https://www.modb.pro/u/4347
CSDN :https://blog.csdn.net/JiekeXu
ITPUB:https://blog.itpub.net/69968215
腾讯云:https://cloud.tencent.com/developer/user/5645107
——————————————————————————

facebook_pro_light_1920 × 1080  副本.png

最后修改时间:2026-09-29 00:07:28
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论