大家好,我是 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 原生与智能化 相关的特性和能力,文中若有不足及错误之处,欢迎私信交流。

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

| 项目 | 详情 |
|---|---|
| 测试版本 | 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]$

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 参数在 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))

第 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
开启并行的三个途径(本会话均实际执行验证):
- SQL Hint(最直接):
SELECT /*+ MAX_PARALLEL_DEGREE(4) */ ...—— 本节主用方法; - 全局内存参数:
SP_SET_PARA_VALUE(2,'MAX_PARALLEL_DEGREE',4);—— 改全局 FILE_VALUE; - 会话级参数:
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) 表明按分组键做并行聚合。

第 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
解读: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 文本(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;

执行结果:
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 呈现,可与哈希连接(混合查询)自由组合。

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

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(连接被重置,实例进程崩溃)
崩溃排除过程(逐步执行):
- 现象定位:
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.——实例已死); - 恢复:
DmServiceDAMENG restart(stop+start 均 [OK]),随后查 dm.ini 发现HNSW_SHARD_SEARCH_PARALLEL_DEGREE = 8残留在文件中; - 对照验证 A(=1):
SP_SET_PARA_VALUE(1,'HNSW_SHARD_SEARCH_PARALLEL_DEGREE',1);后同一 ANN 查询正常,实测 1.210s(冷)→ 40.456ms(热),稳定复跑 3 次无异常; - 对照验证 B(=8):再次改回 8 后同一查询再次崩溃(connection lost,第三次复现);
- 修复:重启实例 →
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>

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),故未能完成"启用审计规则→产生审计记录→安全员查询记录"全链路实测;但 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 亮点(本次实测确认)
- 批量装载:百万行 950ms(105 万行/秒),工程调优价值极大。
- 单表多索引扫描:3 索引 + ROWID 哈希双连接 + 零回表,多谓词 OLTP 查询利器(初态实测加速 5.4~5.8×;对统计信息敏感、Hint 非强制)。
- 查询内并行:热数据 2.87×、冷数据 6.8× 加速,开启路径三条(Hint/全局/会话)与 EXPLAIN 判定法全部实证。
- 栈式虚拟机:~510 万次迭代/秒的 PL/SQL 解释性能,V$VMS 提供堆栈级可观测性。
- 向量能力完整:VECTOR 类型、4 类索引(HNSW/IVFFLAT/BMP/DISKANN 全实例化)、精确/近似查询语法一体化、VSEK 算子可 EXPLAIN、召回率 100%(10/10)、混合查询与关系引擎无缝融合。
- 向量装载/建索引性能:50 万向量 6.7s;IVFFLAT 秒级建索引、DISKANN 121ms 建成——规模化 AI 应用可用性高。
- 多模型融合:向量↔JSON 双向转换、JSON_TABLE 行化、JSON_VALUE/EXISTS/QUERY 完备。
- 安全分权被内核强执行:三次越权均被拒绝且错误码精确(-5578/-5549/-5504)。
- 无锁热备:备份与写入并发零阻塞(时间线证据);LSN 闪回与回收站 DROP 恢复两模式可用。
- 故障可诊断性:测试期间把实例"打崩"(SIGSEGV/connection lost)后,DmServiceDAMENG restart + 日志取证(dm_DMSERVER 日志 FATAL 行带信号码与线程号)定位到参数根因并完成闭环修复——崩溃恢复路径可用、问题可归因可回退。
4.2 发现的坑与限制
- 向量距离度量参数必须裸写且仅支持
cosine/dot/euclidean三种字面量:'cosine'(带引号)→[-2007]语法错(报错位置有误导性);l2/l1/euclid/manhat字面量不存在 →[-14322](欧式距离字面量为euclidean,曼哈顿须用运算符<+>)。官方未说明,建议明示全部合法字面量清单。 - 一个向量列只允许一个向量索引;对比测试需复制表。
- DISKANN 索引官方手册无语法(实测 TYPE DISKANN 可用),建议文档补齐。
- 结果集缓存:规则判定视图存在(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);全自动填充本次负载未观测到——建议官方给出自动缓存生效条件清单与静态参数的在线生效途径。 - JSON
->/->>等运算符与 JSON_MODE 绑定,Oracle 兼容模式(默认)下不可用,迁移 Oracle 应用需注意。 - SYSSSO 初始未激活(EXPIRED)且 SYSDBA 无权激活/改密——开箱默认部署需在初始化向导中完成三权口令规划。
#字符不能出现在 disql 口令中(与扩展选项冲突)。ALTER SYSTEM SET 'ENABLE_FLASHBACK'=1会话期生效、重启失效(未落 ini),生产固化需改 dm.ini。- 【重要,实测崩溃】
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 完整排查记录)。 SP_SET_PARA_VALUE(2,...)(全局 scope)会把参数值持久化写入 dm.ini 文件——参数实验若不回退,实例重启后仍生效(本次即因此遗留 8 并触发第 9 条崩溃);实验型调参务必"改前记录原值、改后立即回退",dm.ini 手动修改也要留备份。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
——————————————————————————





