达梦数据库对象管理

达梦数据库对象管理学习笔记:从模式、表到权限的完整梳理

来源总览: 本文主要参考 03_doc/DM8系统管理员手册.md 第 8 章"管理模式对象的空间"、第 13 章"模式对象的常规管理"、第 14 章"数据库布局和存储管理";03_doc/DM8_SQL语言使用手册.md 第 3 章数据定义语句、第 6 章视图、第 7 章物化视图、第 14 章触发器、第 15 章同义词;03_doc/DM8安全管理.md 第 3 章"自主访问控制"。

一、整体认识:数据库对象到底是什么

数据库对象不是一个单一概念。站在 DBA 或开发人员的角度看,所谓对象管理,其实是在管理数据库里一批"有名字、有归属、有权限、有依赖关系"的东西。

在 DM 中,模式对象主要包括:

类型 典型对象 主要作用
数据承载对象 表、临时表、分区表、HUGE 表 存放业务数据
访问加速对象 索引、全文索引、位图索引 提高查询效率
逻辑封装对象 视图、物化视图、同义词 简化访问、隔离细节
程序对象 触发器、过程、函数、包 封装业务逻辑或自动动作
生成类对象 序列 生成连续或近似连续的数值
安全相关对象 用户、角色、权限 控制谁能做什么
存储相关对象 表空间、数据文件 决定对象数据落到哪里

官方手册里有一个很关键的区分:表、视图、索引、触发器、存储过程、序列、同义词等属于"模式对象";用户、角色、权限、表空间属于"非模式对象"。这个区分非常重要,因为它决定了对象命名、访问路径和权限控制方式。

可以用一句话理解:

模式对象是业务对象和 SQL 对象的主体,非模式对象是支撑这些对象被创建、存储和访问的管理结构。

比如一张业务表 SALES.ORDER_INFO

  • SALES 是模式名。
  • ORDER_INFO 是表对象。
  • 表中的数据实际存放在某个表空间的数据文件里。
  • 用户要访问它,需要有 SALES.ORDER_INFO 上的对象权限,或者拥有更高层级的数据库权限。
  • 如果这张表上有索引、触发器、视图、外键,它还会和其他对象形成依赖关系。

所以对象管理不是简单的 CREATEDROP,而是要同时考虑命名空间、存储、权限和依赖。

二、模式:对象管理的第一层命名空间

模式可以理解为数据库对象的命名空间。一个模式下面可以有表、视图、索引、序列、过程、同义词等对象。

DM 中系统会为每个用户自动建立一个与用户名同名的默认模式。比如创建用户 U_APP 后,通常也会有一个默认模式 U_APP。如果用户在没有显式指定模式名的情况下创建表,表一般会落到当前模式下。

sql 复制代码
CREATE USER U_APP IDENTIFIED BY "U_APP_123";

-- 登录 U_APP 后,如果当前模式为 U_APP:
CREATE TABLE T_ORDER (
  ID INT,
  ORDER_NO VARCHAR(50)
);

-- 这张表可以理解为 U_APP.T_ORDER
SELECT * FROM U_APP.T_ORDER;

访问对象时,建议养成显式写模式名的习惯,尤其是在脚本、迁移、授权、排查环境中。

sql 复制代码
SELECT * FROM DMHR.EMPLOYEE;
SELECT * FROM SYSDBA.T_TEST;

这样做的好处是减少歧义。因为不同模式下可以存在同名对象,例如:

text 复制代码
U_APP.T_CONFIG
U_REPORT.T_CONFIG

如果只写 T_CONFIG,数据库会按当前模式和对象解析规则去找。学习阶段可能不觉得有问题,但到了多用户、多模式、迁移或权限排查场景,不写模式名会让问题变得难判断。

CREATE SCHEMA 不只是建一个空模式

手册里提到,CREATE SCHEMA 可以创建空模式,也可以在创建模式时一起创建多个模式对象。例如:

sql 复制代码
CREATE SCHEMA TEST
CREATE SEQUENCE ADDRESS_SEQ INCREMENT BY 1
CREATE TABLE ADDRESS (
  ADDRESSID INT,
  ADDRESS1 VARCHAR(60) NOT NULL,
  CITY VARCHAR(30) NOT NULL,
  POSTALCODE VARCHAR(15) NOT NULL
)
CREATE TABLE ADDRESS_TYPE (
  ADDRESS_TYPEID INT PRIMARY KEY,
  NAME VARCHAR(50) NOT NULL
);

这说明模式不是"用户本身",而是对象集合。一个用户可以创建多个模式,一个模式里的对象也可以被多个有权限的用户访问。

当前模式和对象解析

在 SQL 中,模式名.对象名 是最清晰的引用方式。如果没有写模式名,DM 会在当前模式下查找对象。

sql 复制代码
-- 设置当前模式
SET SCHEMA TEST;

-- 等价于访问 TEST.ADDRESS
SELECT * FROM ADDRESS;

这里有一个容易混淆的点:SQL 语句对象解析和 DMSQL 程序对象解析不完全一样。系统管理员手册中提到,在 SQL 语句里,A.B 优先按"模式.对象"解析;而在 DMSQL 程序里,A.B 可能优先按"本模式下包.对象"解析。写程序对象时,命名要尽量避免包名、模式名、对象名互相打架。

三、表:数据库对象管理的核心

表是对象管理中最核心的对象,因为大多数索引、视图、物化视图、触发器、权限和统计信息最终都围绕表展开。

一张表至少要考虑这些内容:

  • 表属于哪个模式。
  • 表放在哪个表空间。
  • 列的数据类型是否合适。
  • 主键、唯一约束、外键、检查约束是否完整。
  • 是否需要分区、临时表或 HUGE 表。
  • 后续查询是否需要索引和统计信息。
  • 谁可以查询、插入、修改或删除这张表。

一个普通表可以这样创建:

sql 复制代码
CREATE TABLE APP_ORDER (
  ID INT PRIMARY KEY,
  ORDER_NO VARCHAR(50) NOT NULL,
  CUSTOMER_NAME VARCHAR(100),
  AMOUNT DECIMAL(18,2),
  CREATE_TIME DATETIME DEFAULT SYSDATE
);

如果要明确模式和表空间,可以写得更完整一些:

sql 复制代码
CREATE TABLE U_APP.APP_ORDER (
  ID INT PRIMARY KEY,
  ORDER_NO VARCHAR(50) NOT NULL,
  CUSTOMER_NAME VARCHAR(100),
  AMOUNT DECIMAL(18,2),
  CREATE_TIME DATETIME DEFAULT SYSDATE
)
TABLESPACE MAIN;

表对象后期经常需要调整。ALTER TABLE 支持增加列、删除列、修改列类型、增加或删除约束、重命名表或列、移动表空间、启用或禁用约束等。

sql 复制代码
ALTER TABLE U_APP.APP_ORDER ADD COLUMN STATUS VARCHAR(20) DEFAULT 'NEW';

ALTER TABLE U_APP.APP_ORDER RENAME COLUMN CUSTOMER_NAME TO CUST_NAME;

ALTER TABLE U_APP.APP_ORDER ADD CONSTRAINT CK_APP_ORDER_AMOUNT
CHECK (AMOUNT >= 0);

这里需要注意,表结构变更不是孤立操作。比如删除列、改名、删除约束,可能影响视图、触发器、过程、外键和应用 SQL。

约束:比程序判断更靠近数据本身

完整性约束用于限制表中的数据。常见约束包括:

约束 作用
PRIMARY KEY 主键,唯一标识一行
UNIQUE 保证列或列组合唯一
NOT NULL 不允许为空
CHECK 按表达式检查数据
FOREIGN KEY 建立表间引用关系
sql 复制代码
CREATE TABLE U_APP.CUSTOMER (
  ID INT PRIMARY KEY,
  NAME VARCHAR(100) NOT NULL,
  PHONE VARCHAR(30),
  STATUS VARCHAR(20) CHECK (STATUS IN ('ACTIVE', 'DISABLED'))
);

CREATE TABLE U_APP.APP_ORDER (
  ID INT PRIMARY KEY,
  CUSTOMER_ID INT,
  ORDER_NO VARCHAR(50) UNIQUE,
  AMOUNT DECIMAL(18,2) CHECK (AMOUNT >= 0),
  CONSTRAINT FK_ORDER_CUSTOMER
    FOREIGN KEY (CUSTOMER_ID)
    REFERENCES U_APP.CUSTOMER(ID)
);

约束有启用和禁用状态。导入大量数据、批处理修改或迁移数据时,可能会临时禁用某些约束以提高速度,但操作结束后应尽快启用并校验。

sql 复制代码
ALTER TABLE U_APP.APP_ORDER DISABLE CONSTRAINT CK_APP_ORDER_AMOUNT;

ALTER TABLE U_APP.APP_ORDER ENABLE CONSTRAINT CK_APP_ORDER_AMOUNT;

需要记住:禁用约束可能让不符合规则的数据进入表中,所以不能把它当成普通优化手段随便用。

DELETE、TRUNCATE、DROP 的区别

对象管理里经常遇到三类"删除":

操作 删除什么 是否保留表结构
DELETE 删除满足条件的数据行 保留
TRUNCATE TABLE 清空整张表数据 保留
DROP TABLE 删除表对象本身 不保留
sql 复制代码
DELETE FROM U_APP.APP_ORDER WHERE STATUS = 'CANCELLED';

TRUNCATE TABLE U_APP.APP_ORDER;

DROP TABLE U_APP.APP_ORDER CASCADE;

TRUNCATE 通常比 DELETE 清空全表更快,但它不会触发表上的 DELETE 触发器。DROP TABLE 删除表以后,表上的索引也会被删除,用户在该表上的权限也会自动取消。

实际操作时,先问自己一句:是要删数据,还是要删对象?如果只是清空数据,不要误用 DROP

四、表空间和空间管理:对象最终要落到存储上

模式解决对象"属于谁"和"叫什么"的问题,表空间解决对象"放在哪里"的问题。

表空间由数据文件组成,表和索引等对象的数据最终会落在表空间的数据文件里。创建表空间时要指定数据文件:

sql 复制代码
CREATE TABLESPACE TS_APP
DATAFILE '/dmdata/DAMENG/TS_APP01.DBF' SIZE 128;

表空间可以通过添加数据文件或扩展已有数据文件来扩容。系统管理员手册中也提到,可以通过动态视图查看表空间和数据文件对应关系:

sql 复制代码
SELECT ts.NAME, df.PATH
FROM V$TABLESPACE ts, V$DATAFILE df
WHERE ts.ID = df.GROUP_ID;

对象空间管理还有两个常见问题。

第一,用户可能有表空间配额限制。如果用户超过指定表空间配额,创建表、创建索引或插入更新数据时会报空间不足。

sql 复制代码
CREATE USER TEST_USER
IDENTIFIED BY "TEST_password_123"
QUOTA 50M ON TS_APP;

ALTER USER TEST_USER QUOTA 100M ON TS_APP;

第二,单个表对象也可以设置磁盘空间限制:

sql 复制代码
CREATE TABLE TEST (
  SNO INT,
  MYINFO VARCHAR
) DISKSPACE LIMIT 500;

ALTER TABLE TEST MODIFY DISKSPACE LIMIT 50;

查看对象空间时,可以使用系统函数:

sql 复制代码
-- 查看用户占用空间,返回页数
SELECT USER_USED_SPACE('TEST_USER');

-- 查看表对象占用空间
SELECT TABLE_USED_SPACE('SYSDBA', 'TEST');

-- 查看表实际使用页数
SELECT TABLE_USED_PAGES('SYSDBA', 'TEST');

这里的学习重点不是背函数,而是建立一个意识:对象管理一定要和空间管理结合。表建得出来,不代表能长期稳定写入;索引能提升查询,也会占空间;分区和表空间规划不合理,后期维护会变复杂。

五、索引:提高查询效率,但不是越多越好

索引的作用是提高查询效率。官方手册中也提醒,索引会降低影响索引列值的 INSERTUPDATEDELETE 执行效率,因为数据库不仅要维护表数据,还要维护索引数据。

最常见的索引创建方式:

sql 复制代码
CREATE INDEX IDX_ORDER_NO
ON U_APP.APP_ORDER(ORDER_NO);

CREATE UNIQUE INDEX UK_ORDER_NO
ON U_APP.APP_ORDER(ORDER_NO);

索引适合这些场景:

  • 经常按某列或某几列过滤。
  • 经常按某列排序。
  • 表数据量较大,全表扫描成本高。
  • 查询条件稳定、重复出现。

例如订单号经常用于精确查询:

sql 复制代码
SELECT *
FROM U_APP.APP_ORDER
WHERE ORDER_NO = 'SO202606120001';

这时 ORDER_NO 上的索引通常有价值。

但索引不是越多越好。下面几种情况要谨慎:

  • 小表上建太多索引,收益有限。
  • 频繁写入的表上建太多索引,会拖慢写入。
  • 低选择性的列建普通 B 树索引,效果可能不好。
  • 经常变化的列建索引,维护成本高。
  • 对查询条件中频繁使用函数的列,普通索引可能用不上。

函数索引

如果查询经常使用表达式或函数,可以考虑函数索引。例如:

sql 复制代码
CREATE INDEX IDX_SALES_DIFF
ON SALES.SALESPERSON(SALESTHISYEAR - SALESLASTYEAR);

函数索引适合表达式过滤,但也有限制。手册中特别说明,函数索引表达式不能包含不确定函数,例如 SYSDATERAND 等。如果使用自定义函数,函数要具备确定性。

可见、不可见、无效和重建

DM 支持修改索引状态:

sql 复制代码
ALTER INDEX IDX_ORDER_NO INVISIBLE;
ALTER INDEX IDX_ORDER_NO VISIBLE;

ALTER INDEX IDX_ORDER_NO UNUSABLE;
ALTER INDEX IDX_ORDER_NO REBUILD;

可以这样理解:

  • VISIBLE:优化器可以考虑使用这个索引。
  • INVISIBLE:优化器不使用这个索引,可用于测试去掉索引后的执行计划影响。
  • UNUSABLE:索引无效,系统不再维护,需要 REBUILD 或重建。
  • REBUILD:重建索引,让索引恢复有效。

生产环境里,不建议随便把索引设成无效,尤其是主键或唯一约束相关索引。学习和测试环境可以用它理解执行计划和索引维护机制。

索引监控

手册中提到可以通过 MONITORING USAGE 监控索引使用情况,相关信息可查看 V$OBJECT_USAGE

sql 复制代码
ALTER INDEX IDX_ORDER_NO MONITORING USAGE;

SELECT *
FROM V$OBJECT_USAGE;

ALTER INDEX IDX_ORDER_NO NOMONITORING USAGE;

这对清理无效索引很有帮助。很多系统运行久了以后,会积累一些"看起来重要但没人用"的索引。是否删除索引不能只凭感觉,最好结合执行计划、监控结果、业务 SQL 和变更窗口综合判断。

六、统计信息:让优化器更了解数据

索引解决的是访问路径问题,统计信息解决的是优化器判断成本的问题。

优化器要决定走索引还是全表扫描、先连接哪张表、使用什么连接方式,都需要了解表的数据量、列分布、索引情况。如果统计信息过旧,执行计划就可能不理想。

DM 支持为表、列和索引生成统计信息。

为表生成统计信息:

sql 复制代码
STAT ON SYS.SYSOBJECTS;

为列生成统计信息,指定采样率:

sql 复制代码
STAT 30 ON SYS.SYSOBJECTS(ID);

为索引生成统计信息:

sql 复制代码
STAT 50 ON INDEX PURCHASING.S1;

也可以指定并行度:

sql 复制代码
STAT /*+ PARALLEL(12) */ ON SYS.SYSOBJECTS;

需要注意,手册中明确说明 STAT 语句会导致当前事务提交。因此不要在复杂事务中随手执行统计信息收集。

创建索引只是给数据库提供一条可能的路,统计信息则帮助数据库判断这条路值不值得走。表数据变化明显之后,如果查询计划异常,除了看索引,也要想到统计信息。

七、视图:把复杂查询包装成稳定入口

视图是从一个或几个基表或视图导出的虚表。它不直接存放数据,数据仍然存放在基表中。查询视图时,数据库会根据视图定义去访问底层对象。

sql 复制代码
CREATE VIEW U_APP.V_ORDER_VALID AS
SELECT ID, ORDER_NO, CUSTOMER_ID, AMOUNT, CREATE_TIME
FROM U_APP.APP_ORDER
WHERE STATUS <> 'CANCELLED';

视图的价值主要有三点:

  1. 简化查询。把复杂查询封装起来,调用方只查视图。
  2. 隔离结构变化。底层表变化时,可以通过视图维持对外结构相对稳定。
  3. 控制数据暴露。只暴露用户需要看到的列和行。

比如不希望报表用户看到订单内部状态字段,可以只授权查询视图:

sql 复制代码
CREATE VIEW U_APP.V_ORDER_REPORT AS
SELECT ORDER_NO, CUSTOMER_ID, AMOUNT, CREATE_TIME
FROM U_APP.APP_ORDER;

GRANT SELECT ON U_APP.V_ORDER_REPORT TO U_REPORT;

WITH CHECK OPTION

可更新视图可以使用 WITH CHECK OPTION 限制通过视图写入的数据必须满足视图条件。

sql 复制代码
CREATE VIEW U_APP.V_ORDER_POSITIVE AS
SELECT ID, ORDER_NO, AMOUNT
FROM U_APP.APP_ORDER
WHERE AMOUNT >= 0
WITH CHECK OPTION;

这样通过视图插入或更新数据时,必须满足 AMOUNT >= 0。它适合把"只允许操作某个范围内的数据"放到视图层控制。

视图依赖和重编译

视图依赖于基表或其他视图。如果基表删除列、改列名、权限变化,视图可能失效。可以通过编译视图检查合法性:

sql 复制代码
ALTER VIEW U_APP.V_ORDER_REPORT COMPILE;

八、物化视图:用空间换查询速度

普通视图不存放数据,物化视图会存放查询结果。可以把物化视图理解成"带刷新机制的查询结果表"。

官方手册中提到,创建物化视图时会产生两个字典对象:物化视图和物化视图表。物化视图表用于存放真实数据。

sql 复制代码
CREATE MATERIALIZED VIEW U_APP.MV_ORDER_DAILY
REFRESH COMPLETE ON DEMAND AS
SELECT CAST(CREATE_TIME AS DATE) AS ORDER_DATE,
       COUNT(*) AS ORDER_COUNT,
       SUM(AMOUNT) AS TOTAL_AMOUNT
FROM U_APP.APP_ORDER
GROUP BY CAST(CREATE_TIME AS DATE);

刷新物化视图:

sql 复制代码
REFRESH MATERIALIZED VIEW U_APP.MV_ORDER_DAILY COMPLETE;

物化视图适合这些场景:

  • 聚合查询很重,实时性要求不高。
  • 报表反复查询同一批统计结果。
  • 底层表很大,直接汇总成本高。

物化视图也有代价:

  • 占用额外存储空间。
  • 需要刷新,刷新会消耗资源。
  • 快速刷新有较多限制,通常还需要物化视图日志。
  • 底层表发生 TRUNCATE、快速装载、分区交换等操作后,可能需要先完全刷新。

所以物化视图不能简单理解为"高级视图"。它更像一个维护成本更高、但能显著减少重复查询成本的对象。

九、序列:生成主键值,但不要误解为严格连续

序列是数据库实体,用于生成唯一整数值,常用于主键或业务编号的一部分。

sql 复制代码
CREATE SEQUENCE U_APP.SEQ_ORDER_ID
START WITH 1
INCREMENT BY 1
NOCYCLE
CACHE 20;

使用序列:

sql 复制代码
INSERT INTO U_APP.APP_ORDER(ID, ORDER_NO, AMOUNT)
VALUES (U_APP.SEQ_ORDER_ID.NEXTVAL, 'SO202606120001', 100);

常见伪列:

伪列 含义
NEXTVAL 生成并返回下一个序列值
CURRVAL 返回当前会话已经获取过的当前序列值

使用 CURRVAL 前,一般要先在当前会话调用过 NEXTVAL

序列的几个参数很重要:

  • INCREMENT BY:步长,可以为正或负,但不能为 0。
  • START WITH:起始值。
  • MAXVALUE / MINVALUE:最大值和最小值。
  • CYCLE / NOCYCLE:达到边界后是否循环。
  • CACHE / NOCACHE:是否预分配缓存值。
  • ORDER / NOORDER:是否保证请求顺序。

学习序列时要特别注意:序列常用于生成唯一值,但不一定适合做严格无间断编号。因为缓存、事务回滚、失败重试等情况都可能造成序列值跳号。如果业务要求票据号严格连续,应单独设计编号机制,而不是直接依赖普通序列。

修改序列:

sql 复制代码
ALTER SEQUENCE U_APP.SEQ_ORDER_ID INCREMENT BY 10;

ALTER SEQUENCE U_APP.SEQ_ORDER_ID CURRENT VALUE 1000;

ALTER SEQUENCE U_APP.SEQ_ORDER_ID RENAME TO SEQ_ORDER_ID_NEW;

删除序列:

sql 复制代码
DROP SEQUENCE U_APP.SEQ_ORDER_ID_NEW;

十、同义词:给对象起别名,降低访问复杂度

同义词可以给数据库对象提供别名。它可以隐藏对象真实名字和拥有者,也可以简化跨模式访问。

sql 复制代码
CREATE SYNONYM U_APP.S_ORDER FOR U_APP.APP_ORDER;

SELECT * FROM U_APP.S_ORDER;

同义词分为全局同义词和非全局同义词:

sql 复制代码
-- 非全局同义词
CREATE SYNONYM U_REPORT.S_ORDER FOR U_APP.APP_ORDER;

-- 全局同义词
CREATE PUBLIC SYNONYM S_ORDER_PUBLIC FOR U_APP.APP_ORDER;

同义词的好处:

  • 简化长对象名。
  • 降低应用 SQL 对具体模式名的依赖。
  • 对远程对象访问提供一定位置透明性。
  • 在迁移或重构时,可以通过同义词减少 SQL 改动。

但同义词也容易隐藏问题。手册中特别说明,同义词创建时不会检查它指向的对象是否存在;使用时如果目标对象不存在或没有权限,才会报错。

sql 复制代码
CREATE SYNONYM U_APP.S_NOT_EXISTS FOR U_OTHER.T_NOT_EXISTS;

-- 创建可能成功,但查询时报错
SELECT * FROM U_APP.S_NOT_EXISTS;

因此同义词适合做访问入口简化,不适合掩盖混乱的对象归属。命名和文档仍然要清楚。

删除同义词:

sql 复制代码
DROP SYNONYM U_REPORT.S_ORDER;

DROP PUBLIC SYNONYM S_ORDER_PUBLIC;

如果删除全局同义词,必须指定 PUBLIC,因为全局同义词和非全局同义词可以同名。

十一、触发器:自动执行逻辑,但要克制使用

触发器是在特定数据库事件发生时自动执行的程序对象。常见的是表触发器,例如在插入、更新、删除前后执行某段逻辑。

sql 复制代码
CREATE OR REPLACE TRIGGER U_APP.TRG_ORDER_BI
BEFORE INSERT ON U_APP.APP_ORDER
FOR EACH ROW
BEGIN
  IF :NEW.CREATE_TIME IS NULL THEN
    :NEW.CREATE_TIME := SYSDATE;
  END IF;
END;
/

触发器可以用于:

  • 审计某些复杂操作。
  • 维护复杂数据完整性。
  • 自动生成字段值。
  • 做某些安全检查。

但官方手册也提醒了触发器使用原则。能用完整性约束完成的,不建议用触发器替代。原因很简单:约束更简单、更稳定,也更容易被数据库保证。触发器隐藏在 DML 背后,写多了以后会让应用行为变得难预测。

触发器可以启用或禁用:

sql 复制代码
ALTER TRIGGER U_APP.TRG_ORDER_BI DISABLE;

ALTER TRIGGER U_APP.TRG_ORDER_BI ENABLE;

也可以重新编译:

sql 复制代码
ALTER TRIGGER U_APP.TRG_ORDER_BI COMPILE;

大量数据导入时,有时会临时禁用触发器以提升速度,但导入结束后要及时启用,并验证数据是否符合预期。

十二、权限:对象建好了,还要控制谁能访问

对象管理离不开权限。DM 安全管理手册里把权限分为两类:数据库权限和对象权限。

类型 控制范围 示例
数据库权限 能不能执行某类数据库级操作 CREATE TABLECREATE VIEWCREATE USER
对象权限 能不能访问某个具体对象 SELECT ON 表UPDATE ON 表EXECUTE ON 过程

数据库权限示例:

sql 复制代码
GRANT CREATE TABLE TO U_APP;
GRANT CREATE VIEW TO U_APP;

对象权限示例:

sql 复制代码
GRANT SELECT ON U_APP.APP_ORDER TO U_REPORT;

GRANT SELECT, INSERT, UPDATE ON U_APP.APP_ORDER TO U_DEV;

如果允许用户继续把权限转授给别人,可以加 WITH GRANT OPTION

sql 复制代码
GRANT SELECT ON U_APP.APP_ORDER
TO U_REPORT
WITH GRANT OPTION;

回收权限:

sql 复制代码
REVOKE SELECT ON U_APP.APP_ORDER FROM U_REPORT;

如果之前授予了转授权限,回收时可能需要 CASCADE

sql 复制代码
REVOKE SELECT ON U_APP.APP_ORDER FROM U_REPORT CASCADE;

角色:批量管理权限

角色是一组权限的组合。与其给每个用户重复授权,不如先创建角色,再把角色授予用户。

sql 复制代码
CREATE ROLE R_ORDER_QUERY;

GRANT SELECT ON U_APP.APP_ORDER TO R_ORDER_QUERY;

GRANT R_ORDER_QUERY TO U_REPORT;

这样后续如果报表用户越来越多,只要把 R_ORDER_QUERY 授予新用户即可。权限要调整时,也优先调整角色,减少重复授权带来的混乱。

模式级权限

DM 还支持模式权限,即模式级别的对象 ANY 权限,但需要开启相关 INI 参数。比如:

sql 复制代码
GRANT SELECT ANY TABLE ON SCHEMA USER227 TO USER228;

这表示让 USER228 能查询 USER227 模式下的任意表。这个能力很强,应当谨慎使用。对普通业务账号,优先采用具体对象授权或角色授权,避免权限范围过大。

十三、对象依赖:改名、删除前先想清楚影响面

对象之间会有依赖关系。视图依赖表,触发器依赖表,过程可能依赖表和视图,外键依赖主键或唯一约束。同义词虽然只是别名,但目标对象变化后,使用同义词的 SQL 也会受影响。

系统管理员手册中提到,重命名模式对象时要注意:

  • 如果删除原对象再重建,原对象上的授权会失效,需要重新授权。
  • 如果用 ALTER ... RENAME,基于原对象的权限会转移到新对象上。
  • 依赖该对象的视图和 DMSQL 语句块可能失效,需要重新编译。
  • 基于该对象的同义词在使用时可能报错。

例如:

sql 复制代码
ALTER TABLE U_APP.APP_ORDER RENAME TO APP_ORDER_OLD;

这条语句本身很简单,但它影响的可能不只是表名:

  • 应用 SQL 是否写死了原表名?
  • 视图是否依赖原表?
  • 过程、函数、包是否引用原表?
  • 同义词是否指向原表?
  • 权限是否仍然符合预期?

删除对象更要谨慎。很多 DROP 语句都支持 CASCADE,但 CASCADE 的含义是连带处理依赖关系,不是"更强力、更方便"的普通删除。

我的习惯是:删除前先查依赖,改名前先查引用,操作后再编译相关对象。

十四、数据字典:对象排查不能只靠记忆

对象管理最后一定会落到数据字典和系统视图。

系统管理员手册提到,模式对象的信息主要记录在 SYSOBJECTS 系统表中:

sql 复制代码
SELECT *
FROM SYSOBJECTS
WHERE TYPE$ = 'SCHOBJ'
   OR TYPE$ = 'TABOBJ';

SYSOBJECTS 不能保存所有细节,还要结合其他系统表。例如:

要查什么 可关注对象
模式对象基本信息 SYSOBJECTS
索引详细信息 SYSINDEXES
约束信息 SYSCONS
过程、函数、视图定义文本 SYSTEXTS
物化视图信息 SYS.USER_MVIEWS
表空间信息 V$TABLESPACE
数据文件信息 V$DATAFILE
权限列表 V$AUTHORITIES
索引使用监控 V$OBJECT_USAGE

查看视图定义时,可以查询 SYSOBJECTSSYSTEXTS,也可以使用系统过程:

sql 复制代码
CALL SP_VIEWDEF('SYSDBA', 'VIEW1');

排查对象问题时,我会按这个顺序走:

  1. 对象是否存在。
  2. 对象属于哪个模式。
  3. 当前用户是否有权限。
  4. 对象是否有效。
  5. 是否存在依赖对象。
  6. 是否有同义词、视图或过程间接引用。
  7. 表空间和数据文件是否正常。

这比直接问"为什么查不到表"更有效。很多时候,问题不是表不存在,而是当前模式不对、权限不够、同义词指错、对象失效或表空间异常。

十五、学习总结

达梦数据库的对象管理,表面上看是各种 CREATEALTERDROP 语句,真正学起来要把它看成一个体系。

我的理解可以总结成四句话:

  1. 模式负责组织对象,表空间负责承载数据。
  2. 表是核心对象,索引、视图、触发器、序列、同义词大多围绕表展开。
  3. 权限决定对象能否被访问,角色让权限管理更容易维护。
  4. 改名、删除、迁移对象前,要先考虑依赖、授权、统计信息和数据字典。

后续继续深入时,可以围绕三个方向扩展:

  • 对象依赖和对象失效后的重编译机制。
  • 大表、分区表、HUGE 表的空间和索引管理。
  • 结合执行计划分析索引和统计信息是否真正生效。

对象管理不是只为了会写语法,而是为了在真实环境里知道:对象在哪里、谁能访问、改动会影响谁、出问题该从哪里查。把这条线理清以后,再看备份恢复、迁移同步、性能调优和权限安全,都会顺很多。