由于 SID 不匹配,程序集部署失败

Failed assembly deploy due to non-matching SIDs

数据库名称和登录名在下文中是匿名的。有一些答案 在 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 和登录名。

问题一:那么解决办法是修改master数据库的SID,LoginName吗?将 这样做会伤害任何东西还是一个坏主意?

假设您回应说可以更改 master 上的 SID、LoginName,那么, 如何更改 'master' 数据库?嗯,我有 以前没有做过,但可以在这里找到候选解决方案和评论: The database owner SID recorded in the master database differs from the database owner SID

不过这个情况和上面link呈现的情况不一样,我 认为,因为更改必须发生 to/on 主数据库 ala:

  exec sp_changedbowner [BATZ\boink]

问题 2:这是正确的做法吗?

当然,我会与利益相关者核实对主数据库的此类更改是否会 导致不良后果,但我希望在我什至之前在这里得到一些指导 检查一下。

根据@srutzky 的更新答案更新:

  -- 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';

returns:

  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';

returns:

  sid,  name
  0x01, sa

由于数据库中的owner是SA,想把Master中记录的owner改成SA,运行

alter authorization on database::[foo_prod] to sa

是的,SID 确实需要匹配,因为不匹配表明可能有害的数据库正在还原到实例;这是一个保障。

但是,首先我们需要确切地知道我们在看什么。虽然 FOO_PROD 中的记录与 master 中的记录之间的所有者 SID 肯定不匹配(因此出现错误消息),但您的查询并未查看 FOO_PROD 中的值。您的两个查询正在查看 masterFOO_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 服务器实例所属域的有效 Windows 登录名,并且这个特定的 Windows 登录的 SID 为 0x010500000000000515000000C4B7E63D99D15C20332A47A24B100000。如果登录名不存在,希望您能够通过 CREATE LOGIN.

创建它