达梦数据库,启用存储加密测试,性能损耗142.68%,空间膨胀110.43%

说明

测试过程比较单一,仅代表个人观点。

1.存储加密

为了防止用户直接通过数据文件获取用户信息,DM 提供了全面的数据加密的功能,包括:

透明加密
半透明加密
非透明加密

存储加密在保证数据文件安全性的同时,也会带来一定的性能影响,不同的加密算法对性能的影响各有不同,用户需要根据自己的需求来决定是否进行加密以及加密算法的选择。

1.1透明加密

1.1.1全库加密

对 DM 数据库进行全库加密需要在初始化数据库时通过 ENCRYPT_NAME 参数指定全库加密算法,加密密钥由 DM 自动生成。若初始化数据库时不指定 ENCRYPT_NAME 参数,则不进行全库加密。
ENCRYPT_NAME:全库加密使用的算法名。算法可以是 DM 内部支持的加密算法,或者是第三方的加密算法,其中 DM 支持的加密算法可通过查询动态视图 V$CIPHERS 得到,算法名为字符串,不能超过 128 个字节。
此参数在数据库创建成功后无法修改,可通过系统函数 SF_GET_ENCRYPT_NAME()获取此参数的设置值。

1.1.2表空间加密

DM 支持在创建表空间时指定进行透明加密,语法格式为:

CREATE TABLESPACE [IF NOT EXISTS] <表空间名> <数据文件子句> [<数据页缓冲池子句>] [<存储加密子句>] <存储加密子句> ::= ENCRYPT WITH <加密算法> [BY <加密密码>]

1.1.3操作:创建表空间并加密

---创建加密表空间CJC_ENCY
CREATE TABLESPACE CJC_ENCY DATAFILE '/dm8/data/CJC/CJC_ENCY01.DBF' size 128 encrypt with DES_CFB;
---创建测试用户CJC_ENCY
CREATE USER CJC_ENCY IDENTIFIED BY "******" DEFAULT TABLESPACE CJC_ENCY DEFAULT INDEX TABLESPACE CJC_ENCY;
GRANT RESOURCE TO CJC_ENCY;

1.1.4操作:验证表空间已加密

select tablespace_name,encrypted from dba_tablespaces;
行号     tablespace_name encrypted
---------- --------------- ---------
1          SYSTEM          N
2          ROLL            N
3          TEMP            N
4          MAIN            N
5          CJC             N
6          CJC_ENCY        Y
7          MAIN            N
7 rows got

1.1.5表列透明加密

DM 支持对表的列进行透明加密,支持建表时设置加密列,以及修改表定义时设置加密列。存储加密支持所有的列类型,包括大字段类型。用透明加密的方式加密列上的数据时,在数据库中保存加密该列的密钥,执行 DML 语句的过程中系统能自动获取密钥。

语法:

……
<列定义> ::= <不同类型列定义> [<列定义子句>][] [<透明存储加密子句>]
<透明存储加密子句>::= <透明存储加密子句1>|<透明存储加密子句2>
<透明存储加密子句1>::= ENCRYPT [<透明加密用法>] 
<透明存储加密子句2>::= ENCRYPT <透明加密用法><散列选项>
<透明加密用法> ::= WITH <加密算法> [<透明加密选项>]|
		           <透明加密选项> 
<透明加密选项> ::= <透明加密选项1> |<透明加密选项2> |<透明加密选项3> 
<透明加密选项1> ::= AUTO 
<透明加密选项2> ::= AUTO BY <列存储密钥> 
<透明加密选项3> ::= AUTO BY WRAPPED <列存储密钥的密文>

1.1.6操作:创建表为列加密

---创建非加密表空间CJCA
CREATE TABLESPACE CJCA DATAFILE '/dm8/data/CJC/CJCA01.DBF' size 128;
---创建测试用户CJCA
CREATE USER CJCA IDENTIFIED BY "******" DEFAULT TABLESPACE CJCA DEFAULT INDEX TABLESPACE CJCA;
GRANT RESOURCE TO CJCA;
---创建测试表,使用加密列
disql CJCA/******:5238
CREATE TABLE T1(C1 INT, C2 INT ENCRYPT);
CREATE TABLE T2(C1 INT, C2 INT ENCRYPT WITH DES_ECB);
CREATE TABLE T3(C1 INT, C2 INT ENCRYPT WITH DES_ECB HASH WITH MD5 SALT);
CREATE TABLE T4(C1 INT, C2 INT);

1.1.7操作:验证列被加密

select * from DBA_ENCRYPTED_COLUMNS;
行号     OWNER TABLE_NAME COLUMN_NAME ENCRYPTION_ALG SALT INTEGRITY_ALG
---------- ----- ---------- ----------- -------------- ---- -------------
1          CJCA  T1         C2          AES256_CBC     NO   NOMAC
2          CJCA  T2         C2          DES_ECB        NO   NOMAC
3          CJCA  T3         C2          DES_ECB        YES  MD5
已用时间: 15.693(毫秒). 执行号:801.

1.2半透明加密

1.2.1用户半透明加密

创建用户时可以指定存储加密密钥,这个密钥就是为了进行半透明加密时使用的。如果在创建用户时并没有指定存储加密密钥,系统也会自动为用户生成一个默认的加密密钥。

1.2.2表列半透明加密

如果在创建表或修改表时指定对表列进行半透明加密,DM 会使用用户的存储加密密钥对数据进行加密。半透明加密列的密文后追加了 4 个字节的 UID,用户查询数据时,若当前会话用户 ID 与列密文数据中存储的 UID 相同,则返回明文,否则返回 NULL。

1.2.3操作:表列半透明加密

---创建非加密表空间CJCB
CREATE TABLESPACE CJCB DATAFILE '/dm8/data/CJC/CJCB01.DBF' size 128;
---创建测试用户CJCB
CREATE USER CJCB IDENTIFIED BY "******" DEFAULT TABLESPACE CJCB DEFAULT INDEX TABLESPACE CJCB;
GRANT RESOURCE TO CJCB;
---创建测试表,使用加密列
disql CJCB/******:5238
CREATE TABLE T1(C1 INT, C2 INT ENCRYPT MANUAL);
CREATE TABLE T2(C1 INT, C2 INT ENCRYPT WITH DES_ECB MANUAL);
CREATE TABLE T3(C1 INT, C2 INT ENCRYPT WITH DES_ECB MANUAL HASH WITH MD5 SALT);
CREATE TABLE T4(C1 INT, C2 INT ENCRYPT MANUAL HASH WITH MD5 SALT);

1.2.4操作:验证表列透明加密设置成功

select * from DBA_ENCRYPTED_COLUMNS;
行号     OWNER TABLE_NAME COLUMN_NAME ENCRYPTION_ALG SALT INTEGRITY_ALG
---------- ----- ---------- ----------- -------------- ---- -------------
1          CJCA  T1         C2          AES256_CBC     NO   NOMAC
2          CJCA  T2         C2          DES_ECB        NO   NOMAC
3          CJCA  T3         C2          DES_ECB        YES  MD5
4          CJCB  T1         C2          AES256_CBC     NO   NOMAC
5          CJCB  T2         C2          DES_ECB        NO   NOMAC
6          CJCB  T3         C2          DES_ECB        YES  MD5
7          CJCB  T4         C2          AES256_CBC     YES  MD5
7 rows got

1.2.5操作:其他用户查看半透明加密数据测试

--- CJCB用户,对T1表插入数据
disql CJCB/******:5238
insert into t1 values(1,1),(2,2);
commit;
---CJCB用户查看
SQL> select * from cjcb.t1;
行号     C1          C2         
---------- ----------- -----------
1          1           1
2          2           2
已用时间: 0.733(毫秒). 执行号:1803.
---CJCA用户查看CJCB用户t1表数据
grant select any table to CJCA;
disql CJCA/******:5238
SQL> select * from cjcb.t1;
行号     C1          C2         
---------- ----------- -----------
1          1           NULL
2          2           NULL

半透明加密列显示为NULL,实际上有值

1.2.6操作:CJCB用户创建 T5 表,对 C1 列进行按列加密,加密列对用户 CJCA 和 CJC 可见。

--- CJCB用户新增表T5
disql CJCB/******:5238
CREATE TABLE T5(C1 INT ENCRYPT MANUAL USER (CJC,CJCA));
INSERT INTO CJCB.T5 VALUES(100);
COMMIT;
--- SYSDBA用户,查询不到CJCB的T5表C1列数据
disql SYSDBA/******:5238
SQL> select * from CJCB.T5;
行号     C1         
---------- -----------
1          NULL
--- CJCA用户,可以查询到CJCB的T5表C1列数据
disql CJCA/******:5238
SQL> SELECT * FROM CJCB.T5;
行号     C1         
---------- -----------
1          100

1.3非透明加密

DM 对非透明加密的支持是通过对用户提供加解密接口实现的。用户在使用非透明加密时,需要提供密钥并调用加解密接口。采用非透明加密可以保证个人私密数据不被包括 DBA 在内的其他人获取。
非透明加密通过用户调用存储加密函数来进行,DM 提供了一系列的存储加密函数,还提供了一个数据加密包 DBMS_OBFUSCATION_TOOLKIT。

DM 提供了下列存储加密函数:
提供多个加密函数,以 CFALGORITHMSENCRYPT 函数为例:
加密:

CFALGORITHMSENCRYPT(
    SRC VARCHAR/TEXT/CLOB,
    ALGORITHM INT,
    KEY VARCHAR
)

参数说明:
SRC:需要被加密的数据,数据类型可以为 VARCHAR、TEXT 或 CLOB。
ALGORITHM:加密算法 ID。加密算法对应的 ID 可通过查询 V$CIPHERS 得到。
KEY:采用的密钥。

功能说明:
对指定的明文进行加密,并返回密文。src 为 NULL 时, 加密结果也为 NULL。
当输入的参数为非法参数进而导致加密失败时,进行报错。

返回值:
加密后的密文,密文数据类型和 SRC 类型相同。

举例说明:
查看有哪些加密算法:

SQL> select * from V$CIPHERS where CYT_ID=514;
行号     CYT_ID      CYT_NAME   CYT_TYPE    BLOCK_SIZE  KH_SIZE     EXTEND_SIZE WORK_MODE
---------- ----------- ---------- ----------- ----------- ----------- ----------- ---------
1          514         AES128_CBC 1           16          16          16          CBC
已用时间: 0.989(毫秒). 执行号:1207.

创建测试数据,对数据进行加密:

CREATE TABLE CJC.T0311(c1 VARCHAR(200));
INSERT INTO CJC.T0311 VALUES(CFALGORITHMSENCRYPT('达梦数据库非透明加密测试', 514, '仅供测试使用'));
COMMIT;

查询,数据已被加密:

SELECT * FROM CJC.T0311;
行号     c1                                                                                                
---------- --------------------------------------------------------------------------------------------------
1          0C7894F567F5B99354A39B6E0895BE37A7809FCD59BCA0B3B3567C5AAE63E13E2E353A03D9A5F31287358FFA421492ADFE
已用时间: 0.715(毫秒). 执行号:1211

解密:

CFALGORITHMSDECRYPT(
    SRC VARCHAR/TEXT/CLOB,
    ALGORITHM INT,
    KEY VARCHAR
)

参数说明:
SRC:需要被解密的数据,数据类型可以为 VARCHAR、TEXT 或 CLOB。
ALGORITHM:加密算法 ID。加密算法对应的 ID 可通过查询 V$CIPHERS 得到。
KEY:采用的密钥。

功能说明:
对密文进行解密,并得到加密前的相同数据类型的明文。
当输入的参数为非法参数进而导致解密失败时,进行报错。

返回值:
解密后的明文,明文数据类型和 SRC 类型相同。

举例说明:
对数据进行解密:

SQL> SELECT CFALGORITHMSDECRYPT(c1, 514, '仅供测试使用') FROM CJC.T0311;
行号     CFALGORITHMSDECRYPT(c1,514,'仅供测试使用')
---------- ------------------------------------------------
1          达梦数据库非透明加密测试
已用时间: 1.134(毫秒). 执行号:1212.

1.4数据文件strings测试

分别测试非加密、透明加密:加密表空间、透明加密:列加密、非透明加密:列加密对应数据文件的strings值。

01:非加密

disql SYSDBA/******:5238
---创建表空间 CJC01
CREATE TABLESPACE CJC01 DATAFILE '/db/dm8/data/cjc/CJC0101.DBF' size 128;
---创建测试用户 CJC01
CREATE USER CJC01 IDENTIFIED BY "******" DEFAULT TABLESPACE CJC01 DEFAULT INDEX TABLESPACE CJC01;
GRANT RESOURCE TO CJC01;
disql CJC01/******:5238
create table t1(id int,name varchar(10),c1 int);
insert into t1 values(1,'cjc',100);
commit;
仅有1行
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC0101.DBF|wc -l
1
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC0101.DBF
YT&p

02:透明加密:加密表空间

---创建加密表空间CJC02
CREATE TABLESPACE CJC02 DATAFILE '/db/dm8/data/cjc/CJC02.DBF' size 128 encrypt with DES_CFB;
---创建测试用户CJC02
CREATE USER CJC02 IDENTIFIED BY "******" DEFAULT TABLESPACE CJC02 DEFAULT INDEX TABLESPACE CJC02;
GRANT RESOURCE TO CJC02;
disql CJC02/******:5238
create table t1(id int,name varchar(10),c1 int);
insert into t1 values(1,'cjc',100);
commit;
有15354行:
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC02.DBF |wc -l
15354
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC02.DBF |more
FL-Rs
BM}?
Y[>8%
60=y
        2CH
lj#D
BPy 
`TC!.
......

03:透明加密:加密列

---创建表空间 CJC03
CREATE TABLESPACE CJC03 DATAFILE '/db/dm8/data/cjc/CJC03.DBF' size 128;
---创建测试用户 CJC03
CREATE USER CJC03 IDENTIFIED BY "******" DEFAULT TABLESPACE CJC03 DEFAULT INDEX TABLESPACE CJC03;
GRANT RESOURCE TO CJC03;
disql CJC03/******:5238
create table t1(id int,name varchar(10) ENCRYPT WITH DES_ECB,c1 int ENCRYPT WITH DES_ECB);
insert into t1 values(1,'cjc',100);
commit;
有2行:
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC03.DBF|wc -l
2
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC03.DBF
Ep#w
=3/m

04:非透明加密:加密列

---创建表空间 CJC04
CREATE TABLESPACE CJC04 DATAFILE '/db/dm8/data/cjc/CJC04.DBF' size 128;
---创建测试用户 CJC04
CREATE USER CJC04 IDENTIFIED BY "******" DEFAULT TABLESPACE CJC04 DEFAULT INDEX TABLESPACE CJC04;
GRANT RESOURCE TO CJC04;
disql CJC04/******:5238
create table t1(id int,name varchar(10),c1 int);
insert into t1 values(1,CFALGORITHMSENCRYPT('cjc',514,'仅供测试使用'),CFALGORITHMSENCRYPT(100,514,'仅供测试使用'));
[-6111]:字符串转换出错.
已用时间: 0.323(毫秒). 执行号:0.
alter table t1 modify c1 varchar(10);
insert into t1 values(1,CFALGORITHMSENCRYPT('cjc',514,'仅供测试使用'),CFALGORITHMSENCRYPT(100,514,'仅供测试使用'));
commit;
SQL> select * from t1;
行号     id          name                               c1                                
---------- ----------- ---------------------------------- ----------------------------------
1          1           66AC566A88BB54BACE45881D96120DD0FE 400C6FD07E55F2B73BB39539E1447346FE
已用时间: 0.628(毫秒). 执行号:2835809.
select id,CFALGORITHMSDECRYPT(name, 514, '仅供测试使用') name,CFALGORITHMSDECRYPT(c1, 514, '仅供测试使用') c1 from t1;
行号     id          name c1 
---------- ----------- ---- ---
1          1           cjc  100
已用时间: 0.871(毫秒). 执行号:2835811.
有8行,而且直接显示了加密后的值?
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC04.DBF|wc -l
8
dmdba@CJC-DB-001:/db/dm8/data/cjc$strings CJC04.DBF
6`;;
}4ul;
ul!;
wyv;
66AC566A88BB54BACE45881D96120DD0FE
400C6FD07E55F2B73BB39539E1447346FE
'Tg$S
VrsS

1.5加密性能测试

--- CJC用户创建测试数据
---创建非加密表空间CJC
CREATE TABLESPACE CJCB DATAFILE '/dm8/data/CJC/CJCB01.DBF' size 1024;
---创建测试用户CJC
CREATE USER CJCB IDENTIFIED BY "******" DEFAULT TABLESPACE CJCB DEFAULT INDEX TABLESPACE CJCB;
GRANT RESOURCE TO CJC;
---创建测试表,非加密
disql CJC/******:5238
-- 创建销售订单表
CREATE TABLE SALES_ORDER (
    ORDER_ID            BIGINT PRIMARY KEY,        -- 销售单号,使用长整数并设为主键
    SALES_PERSON        VARCHAR(50),                -- 销售员姓名
    PRODUCT_NAME        VARCHAR(100),               -- 销售货物名称
    AMOUNT              DECIMAL(10, 2),              -- 销售金额,保留两位小数
    TRANSACTION_TIME    TIMESTAMP,                  -- 交易时间,精确到时间戳
    MEMO                VARCHAR(200)                 -- 可选的备注列
);
-- 创建存储过程,参数num为要插入的行数
CREATE OR REPLACE PROCEDURE PROC_INSERT_SALES_ORDER(num IN INT)
AS
    i INT;
BEGIN
    i := 1;  -- 初始化循环变量
    WHILE i <= num LOOP
        INSERT INTO SALES_ORDER (
            ORDER_ID, SALES_PERSON, PRODUCT_NAME, AMOUNT, TRANSACTION_TIME, MEMO
        ) VALUES (
            i,  -- 销售单号递增
            DBMS_RANDOM.STRING('U', 8),  -- 随机销售员 [citation:3]
            DBMS_RANDOM.STRING('U', 6),  -- 随机货物 [citation:3]
            ROUND(DBMS_RANDOM.VALUE(10, 10000), 2),  -- 随机金额 [citation:3]
            SYSTIMESTAMP - DBMS_RANDOM.VALUE(1, 365),  -- 随机时间 [citation:6]
            'Note_' || DBMS_RANDOM.STRING('A', 20)  -- 随机备注
        );
        i := i + 1;
        -- 每10000行提交一次,避免事务过大
        IF MOD(i, 10000) = 0 THEN
            COMMIT;
        END IF;
    END LOOP;
    COMMIT;  -- 提交剩余数据
END;
/
-- 调用存储过程,插入1000万行数据
CALL PROC_INSERT_SALES_ORDER(10000000);
DMSQL 过程已成功完成
已用时间: 00:01:39.012. 执行号:3006.
查看测试表大小:
SQL> select count(*) from CJC.SALES_ORDER;
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 0.746(毫秒). 执行号:3102.
SQL> select bytes/1024/1024 from dba_segments where segment_name='SALES_ORDER';
行号     bytes/1024/1024     
---------- --------------------
1          844
已用时间: 102.693(毫秒). 执行号:3101.
---创建非加密表空间CJCC
CREATE TABLESPACE CJCC DATAFILE '/dm8/data/CJC/CJCC01.DBF' size 128;
---创建测试用户CJCC
CREATE USER CJCC IDENTIFIED BY "******" DEFAULT TABLESPACE CJCC DEFAULT INDEX TABLESPACE CJCC;
GRANT RESOURCE TO CJCC;

1.5.1测试1:insert into 插入1千万行数据

CJC使用非加密表空间和非列加密:
CJCA使用的是加密表空间:

CJCB使用的是非加密表空间的列半透明加密:

---列半透明加密:
-- 创建销售订单表,设置加密列
CREATE TABLE SALES_ORDER (
    ORDER_ID            BIGINT PRIMARY KEY,
    SALES_PERSON        VARCHAR(50) ENCRYPT WITH DES_ECB MANUAL,
    PRODUCT_NAME        VARCHAR(100) ENCRYPT WITH DES_ECB MANUAL,
    AMOUNT              DECIMAL(10, 2) ENCRYPT WITH DES_ECB MANUAL,
    TRANSACTION_TIME    TIMESTAMP ENCRYPT WITH DES_ECB MANUAL,
    MEMO                VARCHAR(200) ENCRYPT WITH DES_ECB MANUAL
);

CCJCC使用的是非加密表空间的列透明加密:

--- 列透明加密:
-- 创建销售订单表,设置加密列
CREATE TABLE SALES_ORDER (
    ORDER_ID            BIGINT PRIMARY KEY,
    SALES_PERSON        VARCHAR(50) ENCRYPT WITH DES_ECB,
    PRODUCT_NAME        VARCHAR(100) ENCRYPT WITH DES_ECB,
    AMOUNT              DECIMAL(10, 2) ENCRYPT WITH DES_ECB,
    TRANSACTION_TIME    TIMESTAMP ENCRYPT WITH DES_ECB,
    MEMO                VARCHAR(200) ENCRYPT WITH DES_ECB
);

CJCA用户创建表 SALES_ORDER ,并插入数据:

disql CJCA/******:5238
CJCA用户创建表 SALES_ORDER ,并插入数据:
SQL> insert into CJCA.SALES_ORDER select * from CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:15.759. 执行号:1402.
SQL> commit;
操作已执行
已用时间: 2.921(毫秒). 执行号:1403.
SQL> truncate table CJCA.SALES_ORDER;
操作已执行
已用时间: 17.525(毫秒). 执行号:1404.
SQL> insert into CJCA.SALES_ORDER select * from CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:18.674. 执行号:1405.
SQL> commit;
操作已执行
已用时间: 3.121(毫秒). 执行号:1406.

CJCB用户创建表 SALES_ORDER ,并插入数据:

shutdown immediate;
disql CJCB/******:5238
insert into CJCB.SALES_ORDER select * from CJC.SALES_ORDER;
SQL> insert into CJCB.SALES_ORDER select * from CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:28.454. 执行号:601.
SQL> commit;
操作已执行
已用时间: 2.799(毫秒). 执行号:602.
SQL> truncate table CJCB.SALES_ORDER;
操作已执行
已用时间: 24.268(毫秒). 执行号:603.
SQL> insert into CJCB.SALES_ORDER select * from CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:25.551. 执行号:604.
SQL> COMMIT;
操作已执行
已用时间: 2.756(毫秒). 执行号:605.

CJCC用户创建表 SALES_ORDER ,并插入数据:

shutdown immediate;
disql CJCC/******:5238
SQL> insert into CJCC.SALES_ORDER select * from CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:24.100. 执行号:701.
SQL> commit;
操作已执行
已用时间: 2.369(毫秒). 执行号:702.
SQL> truncate table CJCC.SALES_ORDER;
操作已执行
已用时间: 11.734(毫秒). 执行号:703.
SQL> insert into CJCC.SALES_ORDER select * from CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:25.289. 执行号:704.
SQL> COMMIT;
操作已执行
已用时间: 2.194(毫秒). 执行号:705.

CJC:

[dmdba@cjc-db-03 ~]$ disql CJC/******:5238
服务器[LOCALHOST:5238]:处于主库打开状态
登录使用时间 : 4.357(ms)
disql V8
SQL> CREATE TABLE SALES_ORDER_BAK AS SELECT * FROM SALES_ORDER WHERE 1=2;
SQL> INSERT INTO CJC.SALES_ORDER_BAK SELECT * FROM CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:07.008. 执行号:701.
SQL> COMMIT;
操作已执行
已用时间: 2.579(毫秒). 执行号:702.
SQL> TRUNCATE TABLE CJC.SALES_ORDER_BAK;
操作已执行
已用时间: 16.635(毫秒). 执行号:703.
SQL> 
SQL> INSERT INTO CJC.SALES_ORDER_BAK SELECT * FROM CJC.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:06.729. 执行号:704.
SQL> COMMIT;
操作已执行
已用时间: 2.689(毫秒). 执行号:705.
SQL> INSERT INTO CJC.SALES_ORDER_BAK SELECT * FROM CJCB.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:06.993. 执行号:707.
SQL> COMMIT;
操作已执行
已用时间: 2.713(毫秒). 执行号:708.
SQL> select owner,bytes/1024/1024 from dba_segments where segment_name='SALES_ORDER' order by 1;
行号     owner bytes/1024/1024     
---------- ----- --------------------
1          CJC   844
2          CJCA  844
3          CJCB  1315
4          CJCC  1122
已用时间: 84.180(毫秒). 执行号:1502.

1.5.2测试2:更新数据

新增测试存储过程,测试单条update SALES_ORDER 表的性能,要求固定的数据,当前 SALES_ORDER 表 ORDER_ID=3行的MEMO列值是Note_neWopbLjXLjxhmOIfKAq,要求更新为 Note_neWopbLjXLjxhmOIfABC,然后再更新回Note_neWopbLjXLjxhmOIfKAq,反复重复10万次,每update一条,commit提交一次

CJC/CJCA/CJCB/CJCC 用户创建测试存储过程:

disql CJC/******:5238
CREATE OR REPLACE PROCEDURE test_update_simple
AS
BEGIN
    FOR i IN 1..100000 LOOP
        IF MOD(i, 2) = 1 THEN
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfABC' WHERE ORDER_ID = 3;
        ELSE
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfKAq' WHERE ORDER_ID = 3;
        END IF;
        COMMIT;
    END LOOP;
END;
/
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:12.328. 执行号:5.
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:20.886. 执行号:1001.
disql CJCA/******:5238
CREATE OR REPLACE PROCEDURE test_update_simple
AS
BEGIN
    FOR i IN 1..100000 LOOP
        IF MOD(i, 2) = 1 THEN
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfABC' WHERE ORDER_ID = 3;
        ELSE
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfKAq' WHERE ORDER_ID = 3;
        END IF;
        COMMIT;
    END LOOP;
END;
/
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:23.786. 执行号:702.
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:23.561. 执行号:701.
disql CJCB/******:5238
CREATE OR REPLACE PROCEDURE test_update_simple
AS
BEGIN
    FOR i IN 1..100000 LOOP
        IF MOD(i, 2) = 1 THEN
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfABC' WHERE ORDER_ID = 3;
        ELSE
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfKAq' WHERE ORDER_ID = 3;
        END IF;
        COMMIT;
    END LOOP;
END;
/
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:20.650. 执行号:802.
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:19.433. 执行号:801
disql CJCC/******:5238
CREATE OR REPLACE PROCEDURE test_update_simple
AS
BEGIN
    FOR i IN 1..100000 LOOP
        IF MOD(i, 2) = 1 THEN
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfABC' WHERE ORDER_ID = 3;
        ELSE
            UPDATE SALES_ORDER SET MEMO = 'Note_neWopbLjXLjxhmOIfKAq' WHERE ORDER_ID = 3;
        END IF;
        COMMIT;
    END LOOP;
END;
/
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:30.450. 执行号:902.
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:15.183. 执行号:901.

1.5.3测试3:查询数据

CJC/CJCA/CJCB/CJCC 用户创建数据查询:

SELECT COUNT(*) FROM (
SELECT SALES_PERSON,PRODUCT_NAME,SUM(amount) FROM SALES_ORDER GROUP BY SALES_PERSON,PRODUCT_NAME ) A;
disql CJC/******:5238
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:09.289. 执行号:1401.
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:09.133. 执行号:1402.
disql CJCA/******:5238
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:11.102. 执行号:1101.
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:09.531. 执行号:1102.
disql CJCB/******:5238
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:14.905. 执行号:1201.
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:12.659. 执行号:1202.
disql CJCC/******:5238
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:13.921. 执行号:1301.
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:12.383. 执行号:1302.

1.5.4测试4:表数据量

插入1000万行相同数据后,表数据量:

SELECT
    (SELECT COUNT(*) FROM CJC.SALES_ORDER) AS CJC_TAB_COUNT,
    (SELECT COUNT(*) FROM CJCA.SALES_ORDER) AS CJCA_TAB_COUNT,
    (SELECT COUNT(*) FROM CJCB.SALES_ORDER) AS CJCB_TAB_COUNT,
(SELECT COUNT(*) FROM CJCC.SALES_ORDER) AS CJCC_TAB_COUNT;
行号     CJC_TAB_COUNT        CJCA_TAB_COUNT       CJCB_TAB_COUNT       CJCC_TAB_COUNT      
---------- -------------------- -------------------- -------------------- --------------------
1          10000000             10000000             10000000             10000000
SQL> select owner,bytes/1024/1024 from dba_segments where segment_name='SALES_ORDER' order by 1;
行号     owner bytes/1024/1024     
---------- ----- --------------------
1          CJC   844
2          CJCA  844
3          CJCB  1315
4          CJCC  1122
已用时间: 84.180(毫秒). 执行号:1502.

1.5.5测试5:非透明加密

非透明加密测试,随机生成的一千万条数据内容和前面测试的SQL不同(带有加解密函数)、数据不同(大小相同),仅供参考。

---创建非加密表空间 CJCD
CREATE TABLESPACE CJCD DATAFILE '/dm8/data/CJC/CJCD01.DBF' size 128;
---创建测试用户CJCD
CREATE USER CJCD IDENTIFIED BY "******" DEFAULT TABLESPACE CJCD DEFAULT INDEX TABLESPACE CJCD;
GRANT RESOURCE TO CJCD;
GRANT SELECT ANY TABLE TO CJCD;
disql CJCD/******:5238
CREATE TABLE SALES_ORDER (
    ORDER_ID            BIGINT PRIMARY KEY,
    SALES_PERSON        VARCHAR(50),
    PRODUCT_NAME        VARCHAR(100),
    AMOUNT              DECIMAL(10, 2),
    TRANSACTION_TIME    TIMESTAMP,
    MEMO                VARCHAR(200)
);
CREATE OR REPLACE PROCEDURE PROC_INSERT_SALES_ORDER(num IN INT)
AS
    i INT;
    v_sales_person_plain VARCHAR(50);
    v_product_name_plain VARCHAR(100);
    v_memo_plain         VARCHAR(200);
BEGIN
    i := 1;
    WHILE i <= num LOOP
        -- 生成随机明文字符串
        v_sales_person_plain := DBMS_RANDOM.STRING('U', 8);      -- 8位大写字母
        v_product_name_plain := DBMS_RANDOM.STRING('U', 6);      -- 6位大写字母
        v_memo_plain         := 'Note_' || DBMS_RANDOM.STRING('A', 20);  -- 带前缀的随机字符串
        -- 插入加密后的数据
        INSERT INTO SALES_ORDER (
            ORDER_ID,
            SALES_PERSON,
            PRODUCT_NAME,
            AMOUNT,
            TRANSACTION_TIME,
            MEMO
        ) VALUES (
            i,   -- 销售单号递增
            CFALGORITHMSENCRYPT(v_sales_person_plain, 514, '仅供测试使用'),  -- 加密销售员
            CFALGORITHMSENCRYPT(v_product_name_plain, 514, '仅供测试使用'),  -- 加密货物名
            ROUND(DBMS_RANDOM.VALUE(10, 10000), 2),   -- 随机金额
            SYSTIMESTAMP - DBMS_RANDOM.VALUE(1, 365), -- 随机交易时间
            CFALGORITHMSENCRYPT(v_memo_plain, 514, '仅供测试使用')           -- 加密备注
        );
        i := i + 1;
        -- 每10000行提交一次
        IF MOD(i, 10000) = 0 THEN
            COMMIT;
        END IF;
    END LOOP;
    COMMIT;  -- 提交剩余数据
END;
/
SQL> call PROC_INSERT_SALES_ORDER(10000000);
DMSQL 过程已成功完成
已用时间: 00:02:12.892. 执行号:1603.

大数据量插入测试:

CREATE TABLE CJCD.SALES_ORDER_01 AS SELECT * FROM CJCD.SALES_ORDER WHERE 1=2;
SQL> INSERT INTO CJCD.SALES_ORDER_01 SELECT * FROM CJCD.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:16.917. 执行号:1606.
SQL> COMMIT;
操作已执行
已用时间: 9.998(毫秒). 执行号:1607.
SQL> TRUNCATE TABLE CJCD.SALES_ORDER_01;
操作已执行
已用时间: 22.092(毫秒). 执行号:1608.
SQL> INSERT INTO CJCD.SALES_ORDER_01 SELECT * FROM CJCD.SALES_ORDER;
影响行数 10000000
已用时间: 00:00:16.422. 执行号:1609.
SQL> COMMIT;
操作已执行
已用时间: 14.557(毫秒). 执行号:1610.

数据量查看:

SELECT OWNER,SEGMENT_NAME,BYTES/1024/1024 FROM DBA_SEGMENTS WHERE SEGMENT_NAME LIKE 'SALES_ORDER%' ORDER BY 1,2;
行号     OWNER SEGMENT_NAME    BYTES/1024/1024     
---------- ----- --------------- --------------------
1          CJC   SALES_ORDER     844
2          CJC   SALES_ORDER_BAK 844
3          CJCA  SALES_ORDER     844
4          CJCB  SALES_ORDER     1315
5          CJCC  SALES_ORDER     1122
6          CJCD  SALES_ORDER     1776
7          CJCD  SALES_ORDER_01  1776
7 rows got
已用时间: 83.344(毫秒). 执行号:1702

查看数据,SALES_PERSON/PRODUCT_NAME/MEMO 三个列被加密了:

SQL> select * from SALES_ORDER limit 3;
行号     ORDER_ID             SALES_PERSON                       PRODUCT_NAME                       AMOUNT  TRANSACTION_TIME          
---------- -------------------- ---------------------------------- ---------------------------------- ------- --------------------------
           MEMO                                                              
           ------------------------------------------------------------------
1          1                    C1756E55F28329987763721694D268E1FE 5AE8A09A4DA4A5A73491A89844805B97FE 5503.68 2025-05-19 14:02:08.193946
           C222B3F66A6C0B961543B882F392892A2C35028473CD7991FF6A9A4B48953280FE
2          2                    2E9F2DC3A4D58E38A53BF9F17E1FDAF5FE 0556EFD3F77245A2E261310D155A0198FE 7453.94 2026-01-24 22:25:28.114335
           4472A63449F7F0F73A5833F90519F123D8DEAFF360D8C70C9C572A84CCADA69AFE
3          3                    B18FEBB00C41E4E186B0CA5AAF280501FE 2D4D0274AFB2508539E9E0D06AF4730EFE 1883.67 2025-09-13 00:17:56.888145
           E65D579A64ECFE68C29D5F4EB25F5EA14D4E8D2F9DF626818B16BE401A7DC3A7FE
已用时间: 0.792(毫秒). 执行号:1804.

解密数据:

SQL> SELECT CFALGORITHMSDECRYPT(MEMO, 514, '仅供测试使用') FROM CJCD.SALES_ORDER WHERE ORDER_ID=3;
行号     CFALGORITHMSDECRYPT(MEMO,514,'仅供测试使用')
---------- --------------------------------------------------
1          Note_HiIxlTubevebmogJTWIu
已用时间: 1.345(毫秒). 执行号:1805.

更新数据测试:

参考上面最后一版test_update_simple存储过程,
写一个新的存储过程test_update_simple,要求测试单条update SALES_ORDER 表的性能,
表 ORDER_ID=3行的MEMO列值是Note_HiIxlTubevebmogJTWIu,这个是解密后的值,当然,当前的MEMO列是被加密的,需要通过如下方式才能解密:
SELECT CFALGORITHMSDECRYPT(MEMO, 514, ‘仅供测试使用’) FROM CJCD.SALES_ORDER WHERE ORDER_ID=3;
要求更新为Note_HiIxlTubevebmogJTABC,然后再更新回Note_HiIxlTubevebmogJTWIu,反复重复100万次,每update一条,commit提交一次

CREATE OR REPLACE PROCEDURE test_update_simple
AS
    -- 定义两个固定明文字符串
    v_val_a_plain CONSTANT VARCHAR(50) := 'Note_HiIxlTubevebmogJTWIu';
    v_val_b_plain CONSTANT VARCHAR(50) := 'Note_HiIxlTubevebmogJTABC';
    -- 加密算法标识和密钥(与示例一致)
    v_alg        CONSTANT INT          := 514;
    v_key        CONSTANT VARCHAR(50)  := '仅供测试使用';
    i INT;
BEGIN
    -- 循环 10 万次
    FOR i IN 1..100000 LOOP
        IF MOD(i, 2) = 1 THEN
            -- 奇数次:将 MEMO 从 v_val_a_plain 更新为 v_val_b_plain
            UPDATE SALES_ORDER
            SET MEMO = CFALGORITHMSENCRYPT(v_val_b_plain, v_alg, v_key)
            WHERE ORDER_ID = 3
              AND CFALGORITHMSDECRYPT(MEMO, v_alg, v_key) = v_val_a_plain;
        ELSE
            -- 偶数次:将 MEMO 从 v_val_b_plain 更新回 v_val_a_plain
            UPDATE SALES_ORDER
            SET MEMO = CFALGORITHMSENCRYPT(v_val_a_plain, v_alg, v_key)
            WHERE ORDER_ID = 3
              AND CFALGORITHMSDECRYPT(MEMO, v_alg, v_key) = v_val_b_plain;
        END IF;
        -- 每次更新后立即提交
        COMMIT;
    END LOOP;
END;
/
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:21.452. 执行号:1808.
SQL> CALL test_update_simple();
DMSQL 过程已成功完成
已用时间: 00:01:31.433. 执行号:1809.

查询数据:

SELECT COUNT(*) FROM (
SELECT CFALGORITHMSDECRYPT(SALES_PERSON,514, '仅供测试使用'),CFALGORITHMSDECRYPT(PRODUCT_NAME,514, '仅供测试使用'),SUM(amount) FROM SALES_ORDER GROUP BY CFALGORITHMSDECRYPT(SALES_PERSON,514, '仅供测试使用'),CFALGORITHMSDECRYPT(PRODUCT_NAME,514, '仅供测试使用') ) A;
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:25.042. 执行号:1811.
行号     COUNT(*)            
---------- --------------------
1          10000000
已用时间: 00:00:24.027. 执行号:1812.

1.5.6性能测试总结

总结:
存储加密后的存储膨胀:
透明加密:加密表空间:
1000万行数据,存储空间844MB,没有发生膨胀;

半透明加密:非加密表空间:
1000万行数据,存储空间1315MB,膨胀了471MB,膨胀率55.81%。

透明加密:非加密表空间:
1000万行数据,存储空间1122MB,膨胀了278MB,膨胀率32.94%。
非透明加密:非加密表空间:
1000万行数据,存储空间1776MB,膨胀了932MB,膨胀率110.43%。

存储加密后的性能损耗:
透明加密:加密表空间:
插入1000万行数据:耗时17.217秒,比非加密耗时延长10.348秒,性能损耗150.65%。
更新10万行数据,每1行提交1次:耗时83.674秒,比非加密耗时延长7.067秒,性能损耗9.22%
汇总查询,耗时10.32秒,比非加密耗时延长1.109秒,性能损耗12.34%。

半透明加密:非加密表空间,列加密:
插入1000万行数据:耗时27.003秒,比非加密耗时延长20.134秒,性能损耗293.11%。
更新10万行数据,每1行提交1次:耗时80.042秒,比非加密耗时延长3.435秒,性能损耗4.84%
汇总查询,耗时13.782秒,比非加密耗时延长4.571秒,性能损耗49.63%。

透明加密:非加密表空间,列加密:
插入1000万行数据:耗时24.695秒,比非加密耗时延长17.826秒,性能损耗259.51%。
更新10万行数据,每1行提交1次:耗时82.817秒,比非加密耗时延长6.21秒,性能损耗8.11%
汇总查询,耗时13.152秒,比非加密耗时延长3.941秒,性能损耗42.79%。

非透明加密:非加密表空间,列加密:
插入1000万行数据:耗时16.670秒,比非加密耗时延长9.835秒,性能损耗142.68%。
更新10万行数据,每1行提交1次:耗时86.442秒,比非加密耗时延长6.21秒,性能损耗12.84%
汇总查询,耗时24.535秒,比非加密耗时延长15.324秒,性能损耗166.37%。

image.png

2.参考链接:

https://eco.dameng.com/document/dm/zh-cn/pm/storage-encryption.html

欢迎关注我的公众号《 IT小Chen


请使用浏览器的分享功能分享到微信等