一次交付里最小的一套动作 —— 能登录、有地方存、有人能用、能建出表。五步走完,每一条命令后面都跟着真实执行输出;本文只讲 disql,不出现任何图形工具操作。
VTI / SOI / RESOURCE」。
本篇按这套口径授完权限后逐项去查,结果是:RESOURCE 在建对象、SOI 在让元数据查得到、而 VTI 在本版本是个空角色
(系统权限 0 条、对象权限 0 条、嵌套角色 0 个)。第 4 步有撤/授对照实验,你可以自己复跑。| 步骤 | 这条命令产出什么 | 怎么证明它成了 | 最容易错的地方 |
|---|---|---|---|
| 1 · 登录 disql |
一个能执行 SQL 的会话 | 回显 mode is normal, state is open |
口令含 # 会被当成扩展选项;口令错时不会退出,而是掉回交互输入 |
| 2 · 表空间 CREATE TABLESPACE |
一个带数据文件的命名存储区 | dba_data_files 里有这一行 | 在集群里,文件不一定落在你连的那个节点上;DDL 成功时什么都不打印 |
| 3 · 用户 CREATE USER |
一个能登录的账号,带默认表空间 | dba_users 的 DEFAULT_TABLESPACE | 只写在建用户语句里不算数,必须回查这一列 |
| 4 · 授权 GRANT |
建对象 + 查元数据的权限 | dba_role_privs 里有这三行 | 以为授了就什么都能查;VTI 在本版本是空角色 |
| 5 · 建表 CREATE TABLE |
一张真能在里面存数据的表 | user_tables 的 TABLESPACE_NAME | 建表成功 ≠ 落在你要的表空间,必须查 user_tables |
dba_* 字典里对出来,第五条只能在用户自己的 user_tables 里对。
左侧点一步,这里显示该步的完整命令与实测输出。点同一块可取消固定,按 Esc 也可取消。
03134284172-20260803-340005-20093,
四实例 DP 集群(MP 5239 / SP1 5236 / BP1 5237 / BP2 5238),全部 OPEN。
下面所有输出都是从这个环境里原样取的,没有改写、没有补全。
两种连法:带主机端口,或本机 socket。日常交付用第一种,因为客户现场几乎不会让你登到数据库主机上。
# 连指定主机和端口(交付时最常用)
./disql <用户名>/<口令>@<IP>:<端口>
# 连本机默认实例(省掉 IP 和端口)
./disql <用户名>/<口令>
# 口令不方便写在命令行时:先连上,再交互式改连
./disql /nolog
SQL> conn <用户名>/<口令>@<IP>:<端口>
Server[127.0.0.1:5236]:mode is normal, state is open login used time : 2.762(ms) disql V8 SQL>第一行才是登录成功的证据:
mode is normal, state is open。看到这行才说明实例是正常打开状态;
如果实例在 mount 状态,这行会变成 mode is normal, state is mount,后面建表一律失败。
#,disql 会打一堆用法说明
$ ./disql DELIVERY/"Deliv_2026#01"@127.0.0.1:5236
USAGE:CONN[ECT] <logon>
...
<logon_option> ::= #{<extend_option>=<value>[,...]}...
原因是 disql 的登录串语法里 # 是扩展选项分隔符(#{MPP_TYPE=GLOBAL,...}),
#01@127.0.0.1:5236 被当成了一个格式不对的扩展选项。这不是口令错,
但它长得像语法错误,很容易被误判成版本问题去查半天。#;已经设了就用 /nolog 再 conn 交互输入。
$ ./disql SYSDBA/WrongPwd@127.0.0.1:5236 [-2501]:Invalid username or password. disql V8 username:写在脚本里,这一行
username: 就会把整个自动化流程挂住等输入。
脚本一律加 -L(只尝试一次,失败即退):
./disql -L <用户名>/<口令>@<IP>:<端口> -e "select 1"
v$instance,返回的是全部 4 个节点,不是“你连的那一个”。
想知道自己到底连到谁,看登录回显里那行 Server[IP:端口],或者单独查 v$parameter 里的 INSTANCE_NAME。
给业务数据一块独立的存放区,别都堆在 MAIN 上。一条语句建完,顺手带回查。
CREATE TABLESPACE <表空间名>
DATAFILE '<数据文件名>.DBF'
SIZE <初始大小 MB>
AUTOEXTEND ON NEXT <每次扩展 MB> MAXSIZE <上限 MB>;
-- 回查:状态 0 = ONLINE;1 = OFFLINE
SELECT TABLESPACE_NAME, STATUS
FROM DBA_TABLESPACES
WHERE TABLESPACE_NAME = '<表空间名>';
SELECT TABLESPACE_NAME, FILE_NAME,
BYTES/1024/1024 AS MB, AUTOEXTENSIBLE
FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME = '<表空间名>';
TABLESPACE_NAME STATUS --------------- ----------- TS_DELIVERY 0 TABLESPACE_NAME FILE_NAME MB AUTOEXTENSIBLE --------------- ----------------------------------------------- ----- -------------- TS_DELIVERY /home/dmdba/dpc_data/bp1/DAMENG/TS_DELIVERY.DBF 128 YES注意第二张表的路径:文件落在
bp1 节点,而命令是在 sp1 上敲的。
DBA_DATA_FILES.FILE_NAME 给出的真实路径为准。-e 模式下成功时什么都不打印DROP USER 这类语句会回 executed successfully,
但 CREATE TABLESPACE / CREATE USER 在 -e 模式下是静默的。
静默既可能是成功也可能是被吞掉的错误,所以建完立刻回查,这是这套流程里唯一可靠的确认方式。
建一个业务账号,把默认表空间钉在你刚建的那个上。默认表空间决定了这个用户以后不写表空间时数据往哪放。
CREATE USER <用户名>
IDENTIFIED BY "<口令>"
DEFAULT TABLESPACE <表空间名>;
-- 交付后客户要换口令,就是这个语句
ALTER USER <用户名> IDENTIFIED BY "<新口令>";
-- 回查:默认表空间和账号状态
SELECT USERNAME, DEFAULT_TABLESPACE, ACCOUNT_STATUS
FROM DBA_USERS
WHERE USERNAME = '<用户名>';
USERNAME DEFAULT_TABLESPACE ACCOUNT_STATUS -------- ------------------ -------------- DELIVERY TS_DELIVERY OPEN
ACCOUNT_STATUS 是 OPEN 才能登录;如果是 LOCKED,说明账号被锁了,得先 ALTER USER ... UNLOCK。
#(见第 1 步的坑),
其余字母数字下划线组合都能过。改完口令必须用新口令登一次才算验完 ——
ALTER USER 同样是静默成功,不登一次你并不知道改没改上。
按现场口径授 RESOURCE / VTI / SOI,然后逐个查这三个角色到底带了什么权限。
-- 授权
GRANT RESOURCE, VTI, SOI TO <用户名>;
-- 回查:这个用户当前有哪些角色
SELECT GRANTED_ROLE
FROM DBA_ROLE_PRIVS
WHERE GRANTEE = '<用户名>'
ORDER BY 1;
-- 查每个角色到底带了什么(系统权限 / 对象权限)
SELECT GRANTEE, COUNT(*) AS CNT FROM DBA_SYS_PRIVS
WHERE GRANTEE IN ('RESOURCE','SOI','VTI') GROUP BY GRANTEE;
SELECT GRANTEE, COUNT(*) AS CNT FROM DBA_TAB_PRIVS
WHERE GRANTEE IN ('RESOURCE','SOI','VTI') GROUP BY GRANTEE;
SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS
WHERE GRANTEE IN ('RESOURCE','SOI','VTI');
-- 授权前,只有 PUBLIC(建用户自动带) GRANTED_ROLE ------------ PUBLIC -- 授权后 GRANTED_ROLE ------------ PUBLIC RESOURCE SOI VTI
PUBLIC 不需要授,建用户时就有。它已经包含「对自己 schema 里对象」的
SELECT / INSERT / UPDATE / DELETE / EXECUTE 以及建删对象的基础权限(实测 45 条)。
| 角色 | 系统权限 | 对象权限 | 嵌套角色 | 实际作用(实测) |
|---|---|---|---|---|
| RESOURCE | 63 条 | 0 | 0 | CREATE TABLE / INDEX / VIEW / SEQUENCE / PACKAGE / PROCEDURE / TRIGGER,FLASHBACK TABLE,对自己对象的 DML,以及把权限转授给别人 |
| SOI | 0 | 78 | 0 | 对 78 个系统字典表的 SELECT:SYSCOLUMNS、SYSOBJECTS、SYSCONS、DPC_INSTANCE、DPC_LONG_TRX 等 —— 元数据查得到的来源 |
| VTI | 0 | 0 | 0 | 空角色:授予不报错、撤销不报错,不提供任何权限 |
-- 撤掉 VTI,用业务用户查实例信息 REVOKE VTI FROM DELIVERY; SQL> select count(*) c from v$instance; LINEID C ---------- -------------------- 1 4 -- 再授回 VTI,同一条语句 GRANT VTI TO DELIVERY; SQL> select count(*) c from v$instance; LINEID C ---------- -------------------- 1 4撤与不撤结果完全一样。也就是说「能查
v$instance」这件事不是 VTI 给的。
想让非 DBA 用户看某个动态视图,正确做法是单独授:
GRANT SELECT ON <v$视图名> TO <用户名>;
SQL> select count(*) from sys.sysobjects; -- 成功:1152 SQL> select count(*) from dba_users; -- [-5504]:No select privilege on object [SYS.DBA_USERS] SQL> select count(*) from SYSDBA.T_ORDER; -- [-2106]:Invalid table or view name [T_ORDER]查别人 schema 下的表时,DM 报的是「表或视图不存在」而不是「权限不足」。 这是有意为之(不泄露对象是否存在),但排查时极易被读成「表被删了」。 看到
-2106 先想权限,别急着找备份。
用业务身份建表、插两行、查回来。最后一步必须回到 user_tables 看表空间归属。
-- 用业务用户身份执行
CREATE TABLE <表名> (
order_id BIGINT IDENTITY(1,1) PRIMARY KEY,
order_no VARCHAR(32) NOT NULL,
amount DECIMAL(12,2) DEFAULT 0,
status TINYINT DEFAULT 0,
created_at TIMESTAMP DEFAULT SYSDATE
);
INSERT INTO <表名>(order_no, amount, status)
VALUES ('SO20261029001', 1280.00, 0);
COMMIT;
-- 回查数据
SELECT order_id, order_no, amount, status, created_at FROM <表名>;
-- 关键一问:这张表落在哪个表空间
SELECT TABLE_NAME, TABLESPACE_NAME FROM USER_TABLES;
SQL> 2 3 4 5 6 7 executed successfully used time: 28.171(ms). Execute id is 12584813. SQL> affect rows 1 SQL> affect rows 1 SQL> executed successfully SQL> select order_id, order_no, amount, status, created_at from T_ORDER; LINEID ORDER_ID ORDER_NO AMOUNT STATUS CREATED_AT ------ -------- ------------- ------ ------ -------------------------- 1 1 SO20261029001 1280 0 2026-10-29 23:32:06.000000 2 2 SO20261029002 3560.5 1 2026-10-29 23:32:06.000000 SQL> select table_name, tablespace_name from user_tables; LINEID TABLE_NAME TABLESPACE_NAME ------ ---------- --------------- 1 T_ORDER TS_DELIVERY
TABLESPACE_NAME = TS_DELIVERY 是「默认表空间真的生效了」的唯一硬证据。
CREATE USER ... DEFAULT TABLESPACE 成功只说明语句过了,不说明后续建表会落进去。
IDENTITY(1,1) 从 1 开始且不需要序列;
DEFAULT SYSDATE 在插入时自动填了当前时间(两行时间戳相同,因为同一次提交)。
| 要确认的事 | 怎么查 | 合格标准 |
|---|---|---|
| 1 业务用户能登录 | 用新用户执行一次 disql 用户/口令@IP:端口 |
回显 mode is normal, state is open,且进到 SQL> 提示符 |
| 2 默认表空间已钉住 | select DEFAULT_TABLESPACE from DBA_USERS where USERNAME='...' |
等于你指定的那个表空间名 |
| 3 表真的落在里面 | select TABLESPACE_NAME from USER_TABLES(用业务身份) |
等于同一个表空间名 |
| 4 该给的权限到位 | select GRANTED_ROLE from DBA_ROLE_PRIVS where GRANTEE='...' |
含 RESOURCE 与 SOI(PUBLIC 自动带) |
| 5 不该给的没给 | 用业务身份试 select count(*) from dba_users |
报 [-5504]:No select privilege —— 报错才是对的 |
| 6 口令能改、改完能登 | ALTER USER ... IDENTIFIED BY "..." 后用新口令登录 |
登录成功。不登一次就等于没验 |
DBA,前面五项全都正常,问题却埋在那儿。
两个原因叠在一起,但都不是权限的锅:
① 本版本里 VTI 是空角色(系统权限 0 / 对象权限 0 / 嵌套角色 0),授它不产生任何权限;
② v$session 在这个集群版本里根本不存在。实测以 SYSDBA 身份 GRANT SELECT ON v$session TO 用户 会直接报
[-2201]:Invalid database object.;以业务身份查询报 [-2106]:Invalid table or view name [V$SESSION].
会话与节点信息走 DPC_* 系列(DPC_INSTANCE、DPC_LONG_TRX、DPC_HOST 这些),
而它们在 SOI 授予的 78 个对象里,不需要额外授权。
因为集群里 SP 节点不做存储。表空间会被分配到某个 BP 上,文件就落在那个 BP 的目录里。
以 DBA_DATA_FILES.FILE_NAME 为准。本环境实测:在 SP1(5236)上建的表空间,文件落在
bp1 的 dpc_data/bp1/DAMENG/ 下。
而且落到哪个 BP 不固定 —— 同样的语句两轮实测落到了不同位置,所以路径只能现查,不能写死。
数据库本身允许,但 disql 命令行传参时会出问题:# 在登录串里是扩展选项分隔符
(#{MPP_TYPE=GLOBAL,...}),用户/口令#xxx@IP:端口 会被解析成一个坏掉的扩展选项,
disql 直接打印用法说明。
交付时给业务用户设口令避开 # 最省事;已经这么设了,用 disql /nolog 再
conn 用户/口令@IP:端口 交互输入即可。
能收,但没什么理由收:它给的是「对自己 schema 里对象」的基础 DML 和执行权限, 本来就是这个用户该有的东西(实测 45 条)。真回收了,用户连自己的表都操作不了。
要收紧权限,正确方向是别多授系统权限和角色(尤其是 DBA),而不是去动 PUBLIC。
因为 CREATE TABLESPACE / CREATE USER / ALTER USER 在 -e 模式下
成功时什么都不打印。同样一行空白,既可能是成功,也可能是错误被吞了。
只有字典表里的那一行是硬的。这套流程里凡是“看起来成了”的地方,都配了一条回查语句。
v$instance 只返回一行,而不是四行。03134284172-20260803)是空角色,
不代表你手上的版本也一定是。用第 4 步那三条 dba_* 查询自己跑一遍,比记结论可靠。
① 完整报错行(含 [-NNNN] 错误码,DM 的错误码是排查入口);
② 你执行的那条语句原文(口令打码);
③ select banner from v$version; 的输出 —— 版本不同,行为可能不同。
生产库的连接串、真实口令、客户业务表的表结构。定位问题不需要这些。
想让答案别人也能查到?在 Gitee 仓库 提 issue,回复公开可查。