andkylee 发表于 2010-12-27 18:58

使用重启数据库的未认证DBCC dbreboot命令来移交表的所有权

本帖最后由 andkylee 于 2010-12-27 19:03 编辑

参考:http://www.dbainfo.net/one-undocument-dbcc-command-handover-table-ownership.htm
和SQL Server很相似,Sybase ASE数据库有一些未认证的DBCC命令。日常的维护过程中,需要一些Sybase认证的、公开的DBCC命令来完成,比如:检查数据库或者表的一致性、物理存储分配一致性、重建索引等等。对于这些公开的DBCC命令,Sybase公司是提供技术支持保障的。那些未公开的也就是未认证的DBCC命令,仅限Sybase内部工程师使用;Sybase公司不提供技术支持也不会对于此产生的问题负责。所以,不要在生产环境上使用未认证的DBCC命令。在测试环境上研究学习使用倒是可以的。需要记住的是:没人对这些未认证的DBCC产后的后果负责。本篇介绍一个用来关闭或者重启某个用户数据库的未认证DBCC命令:dbcc dbreboot。顺便介绍一个修改对象所有者的方法。因为在ASE中对象的所有权是不能移交的,其它用户只有使用权。这点和中国土地权方面很类似吗?美国人信奉私有制,怎么设计出来这个数据库实现思路?呵呵,有点扯远了~~~这边的测试环境是ASE15.0.3,我不确定从哪个ASE版本开始支持这个dbcc dbreboot命令的。首先用isql连接到ASE15.0.3数据库,先打开在屏幕显示输出信息的选项,
dbcc traceon(3604)go
先来查看一下dbcc dbreboot的用法:执行dbcc help(dbreboot)可以查看使用方法
1> dbcc help(dbreboot)2> godbreboot (report | reboot | reboot_norecovery | shutdown | shutdown_load |restart | restart_norecovery, <dbname1> [, <dbname2> ...])

通过上面的使用方法,可以看到dbreboot命令只有两个参数:1:可操作的类型:reboot,shutdown,restart等2:被操作的用户数据库的名称,不支持数据库ID,也不支持系统数据库
先来查看一下用户数据库ddb下面都有哪些用户和对象
1>use ddb2>go1>select uid,name from sysusers where uid < 1000 order by uid2>go
uid
name
———– ——————————
0 public
1 dbo
3 patrol
5 rep(4 rows affected)
数据库ddb内有两个非系统用户:patrol和rep
1>select uid,count(*) from sysobjects2>group by uid3>order by uid4>go
uid
———– ———–
1
43
5
56(2 rows affected)
用户dbo拥有43个对象,另外56个对象归用户rep所属。下面开始将用户rep拥有的56个对象“移交”给其它的用户:patrol,这里移交的意思就是将对象的所有权转移给其它用户patrol。Sybase ASE中是不支持这么做的。官方的推荐的做法就是重建用户表及其它对象。我这里提供的方法是“非官方”的,或许会存在问题,不过我在多次测试后没发现问题。建议大家在测试开发环境上可以这么做。但是,我感觉这个方法是可行的。在文章后面我将给出验证方法。启用服务器选项“allow updates to system tables”来允许修改系统表,在用户事务内修改表数据来回退错误的操作步骤。
1>begin tran2>go1>update sysobjects2>set uid = 33>where uid = 54>go(56 rows affected)1>commit2>go
以上就将系统表sysobjects中记录对象拥有者uid的信息由rep改成了patrol。内存中的元数据信息是没有办法改的,如果马上进行查询数据库的操作会报错的,也就是说ASE服务器还是“固执”认为被修改所属者的那些表还是属于原来所有者的。如果让ASE认为被修改的这些表属于patrol而不是原来的rep了,方法是重新装载元数据信息。以前的ASE版本中可以通过重启ASE服务器,现在我们可以用dbcc dbreboot命令来重启某个用户数据库,而不是所有的库了。执行dbcc dbreboot(“reboot”,ddb),shutdown是个系统关键字,需要加双引号。
1>dbcc dbreboot("reboot",ddb)2>go———- Shutting Down Database 'ddb' ———-Msg 2202, Level 16, State 1:Server 'TEST', Line 1:You cannot start database shutdown from the database to be shut down.———- Operation on Database 'ddb' Failed ———-必须在master数据库内部执行这个命令:dbcc dbreboot("reboot",ddb)1>use master2>go1>dbcc dbreboot("reboot",ddb)2>go———- Shutting Down Database 'ddb' ———-———- Re-starting Database 'ddb' With Recovery ———-Recovering database 'ddb'.Started estimating recovery log boundaries for database 'ddb'.Database 'ddb', checkpoint=(26118, 15), first=(26118, 15), last=(26125, 13).Completed estimating recovery log boundaries for database 'ddb'.Started ANALYSIS pass for database 'ddb'.Completed ANALYSIS pass for database 'ddb'.Started REDO pass for database 'ddb'. The total number of log records to processis 237.Redo pass of recovery has processed 1 committed and 2 aborted transactions.Completed REDO pass for database 'ddb'.Recovery of database 'ddb' will undo incomplete nested top actions.Started filling free space info for database 'ddb'.Completed filling free space info for database 'ddb'.Started cleaning up the default data cache for database 'ddb'.Completed cleaning up the default data cache for database 'ddb'.Recovery complete.Database 'ddb' is now online.———- Operation on Database 'ddb' Completed Successfully ———-现在,rep拥有的56个对象现在属于patrol用户了。开始验证一下吧。
1>use ddb2>go1>select uid,count(*) from sysobjects2>group by uid3>go
uid
———– ———–
1
43
3
56
(2 rows affected)
sysobjects表中uid由5变成3了。随便找两个表测试一下,
1>select top 2 id,user_name(uid) as username,name
from sysobjects2>where type='U' and uid = 33>go
id
username
name


———– ——————————
—————————————————————————————————————————————————————————————————————————————————————
1392004959 patrol
config


912003249 patrol
conn_properties
(2 rows affected)
1>select count(*) from patrol.config2>go

———–
25
(1 row affected)1>select count(*) from patrol.conn_properties2>go

———–
0
(1 row affected)
查询这两个表的数据是正常的。切换到用patrol用户登录,
C:\Documents and Settings\Administrator>isql -Upatrol -Psybase -Stest1> use ddb2> go1> select count(*) from config2> go

———–
25
(1 row affected)
同样没有问题。再来验证一下,依赖用户表的在用户表config上点右键,属性http://www.dbainfo.net/wp-content/uploads/2010/12/view-table-properties.jpg
      点 依赖性 按钮,
http://www.dbainfo.net/wp-content/uploads/2010/12/view-table-properties-references.jpg可以看到一些存储过程依赖用户表config,没有什么问题。
查看依赖表config的其它对象用如下的SQL语句:
select U.name as username ,O.name as object_name, O.type as object_type
from dbo.sysdepends D, dbo.sysobjects O, dbo.sysusers U
where O.uid = U.uid and O.id = D.id and D.depid = object_id('patrol.config')
–and O.type = 'P'

查看自定义数据类型被引用的情况:
select user_name(T.uid) as datatype_owner,T.name as datatype_name, U.name as user_name,O.name as object_name,C.name as column_name ,O.type as object_type
from dbo.systypes T, dbo.sysusers U, dbo.syscolumns C, dbo.systypes P,dbo.sysobjects O
where T.uid = U.uid and T.usertype = C.usertype and C.id = O.id
and T.usertype >= 100 and T.type = P.type
and P.usertype = (select min(usertype) from ddb.dbo.systypes where type = T.type )

后面还有一些工作要做,使用下面的SQL语句查看数据库ddb内部有哪些表有uid这一列。下面的思路可能有点片面,但是,我感觉Sybase ASE内与用户编号相关的应该用uid这个列名吧?
select object_name(c.id) as object_name, o.typefrom dbo.syscolumns c,dbo.sysobjects owherec.id = o.id and c.name='uid' go
http://www.dbainfo.net/wp-content/uploads/2010/12/dbcc-dbreboot-undocumented-command1.jpg
      与uid相关的对象有8个,排除最后一个视图:sysquerymetrics,需要处理其余7个系统表。在我们的这个例子中,“移交”对象的所有权不涉及到修改用户表sysusers数据的情况,对象信息表sysobjects在上面已经修改过了,在ASE15.0.3文档中sysencryptkeys被解释为留作将来使用,sysusermessages用来存储用户自定义消息,sysqueryplans用来存储抽象查询计划,sysquerymetrics用来存储性能监控指标,这三张表(sysusermessages、sysqueryplans、sysquerymetrics)都都没有数据。最后只剩下两张系统表:systype、sysprotects需要进一步处理。
select uid,usertype,name from dbo.systypeswhere uid = 5go
发现系统表systypes存储了用户rep自定义的数据类型,http://www.dbainfo.net/wp-content/uploads/2010/12/view-table-properties-references2.jpg
      仿照前面修改sysobjects中uid相似的方法,改成systypes存储的rep创建的数据类型归patrol拥有。
use ddbgobegin trangoupdate systypesset uid = 3where uid = 5gocommitgo
这样,rep自定义的数据类型就归patrol用户所有了。
下面查看关于sysproctects系统表的信息,这个表主要存储为用户、组和角色授予或撤消的权限的信息。
select * from sysprotectswhere uid = 5 or grantor = 5go
http://www.dbainfo.net/wp-content/uploads/2010/12/view-table-properties-references3.jpg
      grantor列表示授予者的意思。其实只要将授予者由原来的rep改成现在的patrol即可,既然以前rep没有授予给其他用户权限,那么此处不需要进行修改了。最后总结一下,在ASE15.0.3版本中,估计其它的ASE15.x也是大同小异,移交用户的所有权需要修改7个系统表的数据。在我的测试环境中仅修改了2个系统表(sysobjects和systypes)。这7个系统表是:sysobjects,systypes,sysusers,sysqueryplans,sysquerymetrics,sysprotects, sysencryptkeys。批量修改一遍就行了,
update sysobjects set uid = 3where uid = 5update systypes set uid = 3 where uid = 5update sysusers set uid = 3 where uid = 5update sysqueryplans set uid = 3 where uid = 5update sysquerymetrics set uid = 3 where uid = 5update sysprotects set uid = 3 where uid = 5update sysencryptkeys set uid = 3 where uid = 5这个暂时不需要!
最后重启ASE数据库服务器或者只重启修改的那个用户数据库就可以了。有什么不妥当的地方,欢迎指正!

wfcjz 发表于 2010-12-28 07:49

把你的好东东给我传一份吧1

Eisen 发表于 2010-12-28 09:54

我个人感觉——如果直接修改sysusers比较简单。
例如你这个例子就直接update sysusers set suid=(rep的suid) where uid=3和update sysusers set suid=(patrol的suid) where uid=5
这样直接就交换了两者的owner,而且也不需要重起db。

Eisen 发表于 2010-12-28 09:57

另补充一下,你要检查的系统表应该还有一个—— sysusermessages

andkylee 发表于 2010-12-28 13:27

本帖最后由 andkylee 于 2010-12-28 13:51 编辑

回复 4# Eisen


    文章中涉及到sysusermessages的这个修改了。不过我的测试环境中没有自定义用户消息,sysusermessages表里是空的。

andkylee 发表于 2010-12-28 13:51

回复 3# Eisen


    交换suid只是更换了登录名,不能达到目的。
    需要交换uid。 uid列上有一个唯一索引ncsysusers2,交换的时候弄个中间值转化一下。我试了一下,改完后不用重启用户库。
但是移交对象的所有权是个单向的工作,交换uid会涉及很多“无辜”的。

Eisen 发表于 2010-12-28 14:25

嗯。是的,我那个做法就是全部交换两个login拥有的所有对象。你的比较灵活,可以挑一些出来个别交换。
页: [1]
查看完整版本: 使用重启数据库的未认证DBCC dbreboot命令来移交表的所有权