数据库名称和登录在以下内容中是匿名的。有一些答案 在SO上与这种情况类似,但不完全相同,因此我的问题。
尝试将程序集部署到生产数据库FOO_PROD失败,并显示消息:
Msg 33009, Level 16, State 2, Line 17
The database owner SID recorded in the master database differs from the
database owner SID recorded in database 'FOO_PROD'. You should correct
this situation by resetting the owner of database 'FOO_PROD' using the
ALTER AUTHORIZATION statement.
实际上,以下两个查询证明了SID的不同之处。 首先,我们来看看FOO_PROD的SID:
SELECT SD.[SID],
SL.Name as [LoginName]
FROM master..sysdatabases SD INNER JOIN master..syslogins SL
on SD.SID = SL.SID
WHERE SD.Name = 'FOO_PROD'
显示结果:
SID, LoginName
0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000, BATZ\boink
其次,我们在master数据库中查看FOO_PROD的SID:
SELECT SD.[SID],
SL.Name as [LoginName]
FROM master..sysdatabases SD INNER JOIN master..syslogins SL
on SD.SID = SL.SID
WHERE SD.Name = 'master'
显示结果:
SID, LoginName
0x01, [sa]
我们注意到,就像Visual Studio抱怨的那样,SID确实没有 比赛。它们必须匹配才能继续(显然)。
约束:由于其他几个系统,无法更改FOO_PROD上的SID 使用数据库期望它具有当前具有的SID和LoginName。
问题1:解决方案是否更改主数据库上的SID,LoginName?将 这样做会伤害什么或者是个坏主意吗?
假设您回复说可以在master上更改SID,LoginName,然后, 如何更改“主”数据库?好吧,我 以前没做过,但可以在这里找到候选解决方案和评论: The database owner SID recorded in the master database differs from the database owner SID
但是,这种情况与上面链接中提到的情况不同,我 认为,改变必须发生在主数据库ala上:
exec sp_changedbowner [BATZ\boink]
问题2:这是正确的方法吗?
当然,如果对master数据库进行此类更改,我将与利益相关方核实 导致意想不到的结果,但我希望在此之前得到一些指导 检查一下。
-- Step 1
SELECT sd.[name], sd.[owner_sid], sp.[name]
FROM sys.databases sd
INNER JOIN sys.server_principals sp
ON sp.[sid] = sd.[owner_sid]
WHERE sd.[name] = N'FOO_PROD';
返回:
name, owner_sid, name
FOO_PROD, 0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000, BATZ\boink
然后
-- Step 2
USE [FOO_PROD];
SELECT dp.[sid], sp.[name]
FROM sys.database_principals dp
INNER JOIN sys.server_principals sp
ON sp.[sid] = dp.[sid]
WHERE dp.[name] = N'dbo';
返回:
sid, name
0x01, sa
答案 0 :(得分:2)
是的,SID确实需要匹配,因为不匹配表明可能有害的数据库被恢复到实例;这是一个安全保护。
但是,首先我们需要确切地知道我们正在看什么。虽然FOO_PROD
中的记录与master
中的记录(因此错误消息)之间的所有者SID肯定不匹配,但您的查询不会查看FOO_PROD
中的值。您的两个查询分别针对master
的所有者FOO_PROD
以及master
(再次)针对master
的所有者(此处完全不相关)查看值
第1步
不要将sys*
个对象用于任何内容,因为它们是兼容性视图,因此为SQL Server 2000编写的旧内容仍然可用(dbo.sys*
中的msdb
表仍然有效)。从SQL Server 2005开始,只应使用sys.*
个对象(无需指定master.
)。意思是,使用:
SELECT sd.[name], sd.[owner_sid], sp.[name]
FROM sys.databases sd
INNER JOIN sys.server_principals sp
ON sp.[sid] = sd.[owner_sid]
WHERE sd.[name] = N'FOO_PROD';
第2步
您需要检查数据库本身的值 IN ,因为它记录了所有者的SID,而不是sys.databases
(或者甚至是master..sysdatabases
)。在检查数据库所有者的值时,您需要在sys.database_principals
中查找dbo
用户,如下所示:
USE [FOO_PROD];
SELECT dp.[sid], sp.[name]
FROM sys.database_principals dp
INNER JOIN sys.server_principals sp
ON sp.[sid] = dp.[sid]
WHERE dp.[name] = N'dbo';
第3步
如果您使用的是SQL Server 2005,则需要使用sp_changedbowner
,但从SQL Server 2008开始,不推荐使用存储过程而使用较新的ALTER AUTHORIZATION(尽管它仍然有效)。但是,是的,这是使它们相同的方式,因为它将两个位置同步到您指定的任何一个登录。
但是,您需要确保BATZ\boink
是SQL Server实例所属域的有效Windows登录,并且此特定Windows登录的SID为0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000
。如果登录不存在,希望您能够通过CREATE LOGIN
创建。
答案 1 :(得分:1)
由于数据库中的所有者是SA,并且您想要将Master中记录的所有者更改为SA,只需运行
alter authorization on database::[foo_prod] to sa