master、tempdb、model 和 msdb 是否可以分别具有 1、2、3、4 以外的 database_id?

Ron*_*ldo 8 sql-server system-databases objectid

据我所知,SQL Server系统数据库总是具有相同的 ID,而且我在 Internet 上看到许多维护脚本依赖谓词WHERE database_id > 4将它们从脚本的操作中排除。

另外,如果我SELECT name, schema_id FROM sys.schemas;在新的用户数据库上运行,我会得到:

name                 schema_id
dbo                  1
guest                2
INFORMATION_SCHEMA   3
sys                  4
db_owner             16384
db_accessadmin       16385
db_securityadmin     16386
db_ddladmin          16387
db_backupoperator    16389
db_datareader        16390
db_datawriter        16391
db_denydatareader    16392
db_denydatawriter    16393
Run Code Online (Sandbox Code Playgroud)

我在两个不同的实例上运行了该查询,一个是 SQL Server 2016,另一个是 SQL Server 2005,并且都返回了相同的结果。

问题:

  1. 是否有任何情况(或 sql server 版本)系统数据库 master、tempdb、model 和 msdb 的 database_id 分别不是 1、2、3、4?
  2. 真的可以相信我列出的架构在任何 SQL Server 实例上都具有相同的 ID,以便我可以根据这些 ID 编写维护脚本吗?

Ran*_*gen 15

理论上

以下操作仅用于测试目的。如果您对数据库实例变得不可用、无响应和/或数据丢失感到不满意,请不要尝试任何这些

分离master数据库以尝试重用它的 database_id 是不可能的。

分离model 将导致实例崩溃并且您无法将其重新连接。这导致您必须重建所有系统数据库。此过程会删除所有信息,例如登录名、工作……并且您的用户数据库已分离。

分离Tempdb以尝试重用它的 database_id,通过将其附加回不同的名称导致 database_id 2 未被重用且tempdb无法工作。

name    database_id
master  1
model   3
msdb    4
test3_2__   5
test3_2_    6
tempdb  7
Run Code Online (Sandbox Code Playgroud)

我能把名字改回tempdb,但是实例很乱,我无法正常启动它。

找不到数据库 ID 2。数据库可能尚未激活或正在转换中。一旦数据库可用,重新发出查询。

--->重建所有系统数据库

但是,理论上有 2 个(或更多)选项可以更改msdb系统数据库 ID:

您可以更改msdb通过分离数据库ID msdb,创建新的用户数据库,并最终创建一个新的msdb数据库,而下面的记录的步骤创建一个新的msdb数据库

您可以msdb通过分离msdb、重新附加到不同的名称并将名称改回msdb. 不支持,请不要这样做

首先以“仅主恢复模式”启动 sql server

NET START MSSQL$InstanceName /f /T3608"
Run Code Online (Sandbox Code Playgroud)

分离 msdb 并创建一个新数据库

EXEC sp_detach_db msdb;
GO
CREATE DATABASE test3;
GO
Run Code Online (Sandbox Code Playgroud)

更改msdb文件名,正常重启实例

初始化 msdb:

SQLCMD -E -S<servername> -i"C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Install\instmsdb.sql" -o"C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Install\instmsdb.out"£
Run Code Online (Sandbox Code Playgroud)

查看数据库ID:

SELECT name,database_id 
FROM sys.Databases;

name    database_id
master  1
tempdb  2
model   3
test3   4
...
msdb    12
Run Code Online (Sandbox Code Playgroud)

不支持的方法

2.正常的附着过程 sp_attach_db,并create database ... for attach试图连接时不工作msdb

错误信息:

无法在系统数据库上设置 FILESTREAM 数据库选项,例如“msdb”

您可以做的,仅用于测试目的是创建一个用户数据库, msdb2

CREATE DATABASE msdb2  
    ON (FILENAME = N'X:\MSSQL\DATA\MSDBData.mdf'),   
    (FILENAME = N'X:\MSSQL\DATA\MSDBLog.ldf')   
    FOR ATTACH;  
Run Code Online (Sandbox Code Playgroud)

将数据库重命名为 msdb

ALTER DATABASE msdb2 SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE msdb2 MODIFY NAME = msdb ;
GO  
ALTER DATABASE msdb SET MULTI_USER
Run Code Online (Sandbox Code Playgroud)

正常重启实例

NET STOP MSSQL$InstanceName
NET START MSSQL$InstanceName
Run Code Online (Sandbox Code Playgroud)

并查看database_id's

SELECT name, database_id 
FROM sys.databases;
Run Code Online (Sandbox Code Playgroud)

结果

name    database_id
master  1
tempdb  2
model   3
test    4
...
msdb    10
Run Code Online (Sandbox Code Playgroud)

在实践中

幸运的是,我没有在任何地方看到过这种情况,但是 database_id 4 理论上可以被用户数据库重用。如果发生这种情况,在我的查询中过滤掉系统数据库可能是我遇到的最少的问题。

也就是说,使用WHERE DB_NAME(database_id) NOT IN ('master','tempdb','model','msdb','distribution','ssisdb')是肯定的选择。


AMt*_*two 9

实际上,对于所有当前发布的 SQL Server 版本,这些 ID 将是相同的。

请注意,distribution&SSISDB数据库也是系统数据库,但没有可预测的database_id。

但是,不能保证情况会一直如此,或者将来会继续如此。Microsoft 不提供文档,也不保证这些 ID 始终相同。可以保证有人进入了数据库并弄乱了这些系统模式。

在 SQL Server 的下一版本中,产品团队可以决定对 ID 编号方案进行更改。该更改可以反向移植到 Service Pack 或累积更新中的现有版本。

这在不久的将来可能不太可能发生,因此您可能不必担心。但是,如果您编写了很棒的代码,那么当这种情况发生时,您的代码可能会在十年或两年后仍在使用。然后,你的继任者将有一个老鼠窝需要解开,你的代码不再是“很棒的代码”。

撇开未来的变化不谈,依赖于神秘的、硬编码的 ID 值的代码是不可读的。不是每个人都知道这schema_id > 16384表示一系列特殊模式。(自世纪之交以来,我一直在使用 SQL Server,我会对那行代码感到困惑。)

让您的代码读起来像散文,您将拥有更好、更易于维护的代码。