系统管理员手册中只有一句话,用于设置用户的缺省模式。
个人感觉有点费解,它的作用到底是什么呢?
这里的缺省模式是什么意思?ON SCHEMA 执行完会对数据库有什么影响?它的影响范围是多大?是只影响当前会话吗?
下边我们做一些测试来搞清楚ON SCHEMA :
使用sysdba用户登录
--创建用户
CREATE USER "TEST1" IDENTIFIED BY "TEST123456" HASH WITH SHA512 NO SALT PASSWORD_POLICY 2 ENCRYPT BY "TEST123456"
LIMIT FAILED_LOGIN_ATTEMPS 3, PASSWORD_LOCK_TIME 1, PASSWORD_GRACE_TIME 10 DEFAULT TABLESPACE "MAIN";
--授权
grant "RESOURCE","PUBLIC","SOI" to "TEST1";
grant CREATE TABLE,CREATE SESSION to "TEST1";
--创建新的schema,结尾必须使用/执行
CREATE SCHEMA TEST2 AUTHORIZATION TEST1;
/
--修改用户缺省schema
ALTER USER TEST1 ON SCHEMA "TEST2";
使用TEST1用户登录
disql TEST1/TEST123456
--不指定schema创建表:
SQL> create TABLE TEST_T_1(C1 INT);
操作已执行
已用时间: 3.129(毫秒). 执行号:1301.
--查看表所属schema
SQL> SELECT A.NAME AS SCH_NAME
FROM SYSOBJECTS A
LEFT JOIN SYSOBJECTS B --用于确定表名
ON A.ID = B.SCHID
LEFT JOIN SYSOBJECTS C --用于确定用户名
ON A.PID = C.ID
WHERE B.TYPE$ = 'SCHOBJ'
AND B.SUBTYPE$ = 'UTAB'
AND B.NAME = 'TEST_T_1'
AND C.TYPE$ = 'UR'
AND C.SUBTYPE$='USER'
AND C.NAME = 'TEST1';
行号 SCH_NAME
---------- --------
1 TEST2
已用时间: 1.777(毫秒). 执行号:1302.
可见,如果创建对象是不指定schema,则会创建在缺省schema下。
--SYSDBA会话中执行:
SQL> ALTER USER TEST1 ON SCHEMA TEST2;
操作已执行
已用时间: 2.413(毫秒). 执行号:1013.
##重启数据库,使用操作系统的root用户执行
systemctl restart DmService*
--TEST1用户登录,再次创建表:
SQL> create TABLE TEST_T_3(C1 INT);
操作已执行
已用时间: 2.905(毫秒). 执行号:1701.
SQL> SELECT A.NAME AS SCH_NAME
FROM SYSOBJECTS A
LEFT JOIN SYSOBJECTS B --用于确定表名
ON A.ID = B.SCHID
LEFT JOIN SYSOBJECTS C --用于确定用户名
ON A.PID = C.ID
WHERE B.TYPE$ = 'SCHOBJ'
AND B.SUBTYPE$ = 'UTAB'
AND B.NAME = 'TEST_T_3'
AND C.TYPE$ = 'UR'
AND C.SUBTYPE$='USER'
AND C.NAME = 'TEST1';
行号 SCH_NAME
---------- --------
1 TEST2
已用时间: 2.388(毫秒). 执行号:1702.
SQL> select ut.TABLE_NAME,ut.TABLESPACE_NAME from USER_TABLES ut WHERE ut.TABLE_NAME ='TEST_T_3';
行号 TABLE_NAME TABLESPACE_NAME
---------- ---------- ---------------
1 TEST_T_3 MAIN
已用时间: 17.434(毫秒). 执行号:1703.
--查看当前使用的schema
SQL> SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL;
行号 SYS_CONTEXT('USERENV','CURRENT_SCHEMA')
---------- ---------------------------------------
1 TEST2
已用时间: 1.016(毫秒). 执行号:1704.
可见ALTER USER TEST1 ON SCHEMA TEST2 并不会因为重启失效,所以这个操作属于是数据库级别。
与之相对应的 SET SCHEMA TEST2 ,则是会话级别(等价于 ALTER SESSION SET CURRENT_SCHEMA=TEST2)
这里有个问题:重启不会失效的东西,一定要有持久化存储的位置;而最有可能的存放这个信息的无疑是DBA_USERS,但:
SQL> SET LINESIZE 100
SQL> select * from SYS.DBA_USERS where username='TEST1';
行号 USERNAME USER_ID PASSWORD ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE DEFAULT_TABLESPACE
---------- -------- ----------- -------- -------------- --------- ----------- ------------------
DEFAULT_INDEX_TABLESPACE TEMPORARY_TABLESPACE CREATED PROFILE
------------------------ -------------------- -------------------------- -------
INITIAL_RSRC_CONSUMER_GROUP EXTERNAL_NAME PASSWORD_VERSIONS EDITIONS_ENABLED
--------------------------- ------------- ----------------- ----------------
AUTHENTICATION_TYPE NOWDATE
------------------- -------------------
1 TEST1 50331756 NULL OPEN NULL NULL MAIN
SYSTEM TEMP 2024-12-02 18:40:01.957334 NULL
NULL NULL 2 Y
NDCT_DB_AUTHENT 2024-12-04 23:37:40
已用时间: 11.860(毫秒). 执行号:509.
--显然这个系统视图中并没有关于schema的信息。而数据库中也没有查到以schema命名的字典表。
--使用10002event,搞清楚这个信息到底记录在哪里!
SQL> alter session set events '10002 trace name context forever';
SQL> ALTER USER TEST1 ON SCHEMA TEST1;
SQL> alter session set events '10002 trace name context off';
Tips:
整数值常量,表示只在对应的错误码或事件号触发时执行。其值取负数就对应系统的错误码;
取10000~10999之间的值则专指内部事件号,目前只能取值10001、10002、10003、10046或10053。
10001指操作符的监控事件;
10002指DDL跟踪的事件;
10003指针对全表扫描、嵌套循环连接等特定操作符的监控事件;
10046指SQL语句分析和执行过程监控事件;
10053指优化器的调试追踪事件。
--trace日志中看到如下内容
*** Start trace 10002 event [SESSION ID:139686915374240] ***
[DDL SQL]:
ALTER USER TEST1 ON SCHEMA TEST1;
[EQUIVALENT DML SQL]:
{
SP_LLOG_REPORT_DDL(65540, -1, -1, 'ALTER USER TEST1 ON SCHEMA TEST1;');
{
INT V_DC_FLAG_LEVEL;
INT ISO_LEVEL = -1;
try{
V_DC_FLAG_LEVEL = SF_RESET_DDLCOMMIT_FLAG();
{
SP_VM_SET_SQL('ALTER USER TEST1 ON SCHEMA TEST1;');
SF_LOCK_DICT(1056964608, 3, 0);
UPDATE SYS.SYSOBJECTS SET INFO2 = 0, INFO3 = 4, INFO4 = 281470832739315, INFO5 = 0x000A000048, VERSION = VERSION + 1 WHERE NAME='TEST1' AND TYPE$='UR' AND SUBTYPE$='USER';
UPDATE SYS.SYSUSER$ SET PASSWORD = 'F597936C419D1C0BC05E186B0249D9864C47D2B8E1DACA773DDFB0080E5930F4F72F52ADD60394CB1A801FF97AE7F606FC7877A81E192C1EC870922EE4B68D05',AUTHENT_TYPE = 1,SESS_PER_USER = 0,CONN_IDLE_TIME = 0,FAILED_NUM = 3,LIFE_TIME = 0 ,REUSE_TIME = 0,REUSE_MAX = 0,LOCK_TIME = 1,GRACE_TIME = 10, PWD_POLICY = 2,RN_FLAG = 0WHERE ID = 50331756;
SP_VM_SET_SQL(NULL);
{
SF_REMOVE_DICT_OBJ( 0, 50331756, 'UR', 'USER', 0);
SP_RESET_SESSION_USER(50331756);
}
SF_LOCK_APPLY_ID();
COMMIT;
}
SP_RESTORE_DDLCOMMIT_FLAG(V_DC_FLAG_LEVEL);
}
catch (exception ex){
SP_RESTORE_DDLCOMMIT_FLAG(V_DC_FLAG_LEVEL);
SF_SET_GEN_INS_UREC_FLAG(1);
if (ISO_LEVEL != -1)
SF_SET_TRX_ISO_LEVEL(ISO_LEVEL);
throw;
}
}
}
--多次修改用户的缺省模式之后发现,INFO4表示的就是用户的缺省模式
UPDATE
SYS.SYSOBJECTS
SET INFO2 = 0,
INFO3 = 4,
INFO4 = 281470832739316,
INFO5 = 0x000A000048,
VERSION = VERSION + 1
WHERE NAME='TEST1'
AND TYPE$='UR'
AND SUBTYPE$='USER';
那281470832739316是什么意思呢?
作为DBA,如何快速查询所有用户的缺省模式是什么?(我们总不能挨个登录用户去查上下文吧😂)
通过对SYSOBJECTS中数据的分析,我得出这个结论:
--查询用户信息及其缺省模式:
SELECT A.NAME AS USER_NAME,
A.ID AS USER_ID,
B.NAME AS SHCEMA_NAME,
B.ID AS SHCEMA_ID,
SF_GET_REAL_ROWID(B.ROWID) as REALID,
CASE
WHEN A.INFO4 is null
THEN A.NAME
WHEN (A.INFO4 = 281474976710655)
THEN A.NAME
WHEN (A.INFO4 = B.ID + 281470681743360)
THEN B.NAME
END AS DEFAULT_SHCEMA
FROM SYSOBJECTS A --用于确定用户名
left JOIN SYSOBJECTS B --SCHEMA_NAME
ON A.ID = B.PID
WHERE A.TYPE$ = 'UR' AND A.SUBTYPE$='USER' AND B.TYPE$='SCH'
order by B.ROWID
--其中:
--281474976710655 是INFO4的默认值: (2^48-1)(十六进制:0xFFFFFFFFFFFF) (同时也是rowid的最大值) , 约为 256 TB。
--修改缺省模式后:info4=schema_id + 281470681743360
--281470681743360 (十六进制:0x4000000000000) 这个数字在DM中有什么特殊含义我也无从得知...
思考: schema_id与rowid之间有何关联?数据库中对象的数量能否超过2^48个?
--尝试drop schema
[dmdba@localhost ~]$ disql TEST1/TEST123456
服务器[LOCALHOST:5236]:处于普通打开状态
登录使用时间 : 2.636(ms)
disql V8
--这里切换模式,避免资源占用
SQL> set schema "TEST2";
操作已执行
已用时间: 0.426(毫秒). 执行号:0.
SQL> drop schema "TEST1" restrict;
drop schema "TEST1" restrict;
第1 行附近出现错误[-2506]:试图删除用户[TEST1]的默认模式.
已用时间: 0.339(毫秒). 执行号:0.
SQL> select * fromWHERE CODE = -2506;
行号 CODE ERRINFO
---------- ----------- -------------------------------------
1 -2506 试图删除用户[%s]的默认模式
已用时间: 2.190(毫秒). 执行号:3601.
由此可见,用户TEST1的默认SCHEMA仍然是TEST1。ALTER USER TEST1 ON SCHEMA “TEST2” 只是影响了SQL的执行。
从这些现象来看,用户的默认SCHEMA并不能被修改。其实也可以理解,毕竟从人类的思维习惯来将,表之类的模式对象是属于用户的。
不允许删除用户同名模式可以在一定程度上避免给用户带来困惑。
但,ERR-2101-无效的用户名,可以考虑增加一些详细信息输出。这个错误发生在创建与已有schema同名的用户时。
--此处使用SYSDBA登录
[dmdba@localhost DAMENG]$ disql
disql V8
用户名:
密码:
服务器[LOCALHOST:5236]:处于普通打开状态
登录使用时间 : 3.877(ms)
SQL> set schema TEST1;
操作已执行
已用时间: 0.367(毫秒). 执行号:0.
SQL> SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL;
行号 SYS_CONTEXT('USERENV','CURRENT_SCHEMA')
---------- ---------------------------------------
1 TEST1
已用时间: 1.002(毫秒). 执行号:3302.
--确认当前登录用户是SYSDBA
SQL> SELECT SYS_CONTEXT('USERENV', 'CURRENT_USER') FROM DUAL;
行号 SYS_CONTEXT('USERENV','CURRENT_USER')
---------- -------------------------------------
1 SYSDBA
已用时间: 1.225(毫秒). 执行号:3303.
--不指定SCHEMA创建表
SQL> create TABLE TEST_T_4(C1 INT);
操作已执行
已用时间: 17.093(毫秒). 执行号:3306.
--查看表所属用户和SCHEMA
SQL> SELECT
C.NAME AS USER_NAME,
A.NAME AS SCH_NAME
FROM SYSOBJECTS A
LEFT JOIN SYSOBJECTS B --用于确定表名
ON A.ID = B.SCHID
LEFT JOIN SYSOBJECTS C --用于确定用户名
ON A.PID = C.ID
WHERE B.TYPE$ = 'SCHOBJ'
AND B.SUBTYPE$ = 'UTAB'
AND B.NAME = 'TEST_T_4'
AND C.TYPE$ = 'UR'
AND C.SUBTYPE$='USER';
行号 USER_NAME SCH_NAME
---------- --------- --------
1 TEST1 TEST1
可见使用SYSDBA用户连接数据库时,更改会话的schema后,创建的对象会属于该schema,而该对象所属用户则是拥有该schema的用户。
应用程序在连接数据库时如果指定了SCHEMA,则创建的对象属于该SCHEMA,而不会属于建立连接的用户。[1]
大家在使用数据库的过程中一定要注意用户与模式的区别,在语义分析的过程中,schema作为结构元数据,而用户则是作为权限元数据
类型 | 描述 | 示例 |
---|---|---|
Schema对象 | 属于某个schema的对象,通常用于存储和管理用户的数据、视图、索引等。 | 表、视图、索引、存储过程、触发器、约束等 |
非Schema对象 | 不属于任何特定schema,通常用于数据库的管理、存储、访问控制等。 | 数据库、表空间、用户、权限、数据库链接等 |
达梦管理工具指定schema方式如下:
点击高级,输入schem名
JDBC驱动指定schema的方式如下:
spring.datasource.url=jdbc:dm://192.168.131.135:5236?schema=TEST
SELECT * FROM TEST1.TEST_T_1中的TEST1是什么? DBA_TABLES中的OWNER是什么? ↩︎
文章
阅读量
获赞