SQL Server 2012引入了“包含”数据库的概念,其中数据库所需的所有内容(包括大部分内容)都包含在数据库本身中。在服务器之间移动数据库时,这提供了很大的优势。那么,我想知道,这是否应该是我在设计新数据库时的默认策略。

MSDN列出了所包含数据库的几个缺点,而最大的缺点是缺少对更改跟踪和更改的支持。复制。还有其他吗?如果我不打算使用这些功能,是否有任何理由不使用包含的数据库?

#1 楼

包含数据库的主要目的是使数据库移植到新服务器时更加容易,而无需花费很多精力。考虑到这一点,我将处理一些潜在的问题,这些问题将使迁移变得更加困难-并且大多数都围绕这样一个事实,即所包含的数据库仅部分包含在SQL Server 2012中(实际上并没有强制执行)。


连接字符串

包含数据库的连接字符串必须在连接字符串中显式指定数据库。您不再可以依赖登录名的默认数据库来建立连接;如果您未指定数据库,则SQL Server不会逐步浏览所有包含的数据库,并尝试查找您的凭据可能匹配的任何数据库。


跨数据库查询

即使您在同一服务器上的两个不同的包含数据库中用相同的密码创建了相同的用户,您的应用程序也将无法执行跨数据库查询。用户名和密码可以相同,但不是同一用户。原因是什么?如果您在托管服务器上包含数据库,则不应阻止您与碰巧正在使用同一托管服务器的其他人拥有相同的包含用户。当达到完全包含时(很可能在SQL Server 2012之后的版本中),无论如何绝对禁止跨数据库查询。我强烈建议您不要使用与包含的数据库用户相同的名称创建服务器级别的登录名,并尽量避免在包含的数据库中创建相同的包含的用户名。如果需要运行命中多个包含的数据库的查询,请使用具有适当特权的服务器级登录名进行操作(您可能会认为这是sysadmin,但对于只读查询,这是CONNECT ANY DATABASESELECT ALL USER SECURABLES)。


同义词

大多数3和4部分名称易于识别,并显示在DMV中。但是,如果您创建一个指向3或4部分名称的同义词,则这些名称不会显示在DMV中。因此,如果大量使用同义词,则可能会丢失一些外部依赖关系,这可能会在将数据库迁移到其他服务器时引起问题。我对此问题有所抱怨,但是由于“设计使然”关闭,无法幸免于向新反馈系统的迁移。请注意,DMV还将丢失通过动态SQL构造的三部分和四部分名称。


密码策略

如果创建了包含的数据库用户在没有密码策略的系统上,您可能会发现很难在没有密码策略的系统上创建同一用户。这是因为CREATE USER语法不支持绕过密码策略。我针对此问题提交了一个错误,该错误仍处于打开状态(并且在Connect退出后,它也没有幸免于此)。我觉得很奇怪,在已设置密码策略的系统上,您可以创建一个服务器级别的登录名,该登录名可以轻松绕过该策略,但是您不能创建一个这样做的数据库用户-即使该用户是固有用户更少的安全风险。


归类

由于我们不能再依赖tempdb的归类,因此您可能需要更改当前使用显式的任何代码排序规则或DATABASE_DEFAULT来代替使用CATALOG_DEFAULT。有关某些潜在问题,请参阅此BOL文章。


IntelliSense

如果以包含的用户身份连接到包含的数据库,SSMS将不完全支持IntelliSense。您将获得语法错误的基本下划线,但没有自动完成列表或工具提示以及所有有趣的东西。我提交了一个有关此问题的错误,该错误仍处于打开状态-还有一个在此过程中没有幸免。。


SQL Server数据工具如果您打算使用SSDT进行数据库开发,则当前不完全支持所包含的数据库。这实际上只是意味着,如果您使用某些破坏收容的功能或语法,则构建项目不会失败,因为SSDT当前不知道什么是收容,什么可能破坏它。


ALTER DATABASE

从包含的数据库的上下文中运行ALTER DATABASE命令时,rR而不是ALTER DATABASE foo,您将需要使用ALTER DATABASE CURRENT-这样,如果移动,重命名数据库等,这些命令不需要了解有关它们的外部上下文或引用的任何信息。


其他一些

有些事情您可能仍不应该使用,但是应该在不支持或不建议使用的事物列表中提及,并且不应在包含的数据库中使用:


编号过程绑定对象中的排序规则更改
更改数据捕获
更改跟踪
复制


话虽如此,这些并不一定是缺点对于使用包含的数据库,它们只是您应该注意的问题,并未在正式文档中明确披露。

您还需要确保包含的数据库是否正在运行要迁移,或者是可用性组的一部分或正在被镜像,则所有潜在的目标服务器的sp_configure选项contained database authentication都设置为1。一个,即使它们早于RTM。

评论


您知道为什么不允许临时程序吗?

–乔恩·西格尔(Jon Seigel)
2012年8月2日,下午2:54

@JonSeigel仍然允许它们被部分容纳,但是它们违反了容纳(意味着没有方法可以验证过程访问的实体,因为它的元数据和定义存储在其他位置),因此不建议使用。来自msdn.microsoft.com/zh-cn/library/ff929071.aspx#Limitations:当前允许使用临时存储过程。由于临时存储过程违反了包含性,因此预期将来所包含的数据库版本将不支持它们。

–亚伦·伯特兰(Aaron Bertrand)
2012年8月2日,下午3:12

#2 楼

对于那些有兴趣获取有关包含数据库的更多详细信息的人,我可以建议他们阅读本文http://www.sqlshack.com/contained-databases-in-sql-server/

文章指出了使用包含数据库的主要优点/缺点。

缺点

部分包含的数据库不能使用诸如复制,更改数据捕获,更改跟踪,依赖于模式的对象之类的功能关于具有归类更改的内置函数的说明。 >

将数据库从一台服务器移至另一台服务器非常容易,
因为不会出现孤立的用户问题
元数据存储在包含的数据库中,因此更容易并且具有更高的可移植性
可以对包含的数据库用户同时进行SQL Server和Windows身份验证

本文还可以帮助您:


创建一个新的包含的数据库(通过在SQL Server的“选项”页面中将包含类型设置为“部分”,然后使用T-SQL查询来创建数据库)
使用SQL Server Management Studio连接到包含的数据库(需要指定连接参数中包含的数据库名称)
将现有数据库转换为包含的数据库
在包含的数据库上工作并列出所有包含用户类型的登录名


#3 楼

一个缺点是,不能像登录那样强迫被包含的数据库用户更改自己的密码(MUST_CHANGE)。用户无法管理自己的密码,除非您授予他们更改用户权限,并告诉他们如何使用SQL语句更改密码。他们无法通过用户界面轻松地管理它,或者至少我不知道如何。

另外要注意的是,我在“ PIVOT”和“ UNPIVOT”中发现了意外的和未记录的元数据用法我认为应该只在系统目录(sys.tables / sys.columns / etc)中的“”子句。如msdn中所述:


在包含的数据库中,目录排序规则Latin1_General_100_CI_AS_WS_KS_SC。对于SQL Server所有实例上所有包含的数据库,此排序规则都相同,并且无法更改。


但是他们没有提到“ PIVOT”和“ UNPIVOT”子句也使用系统将其编录为执行机制。因此在迁移过程中,在使用“ PIVOT”和“ UNPIVOT”子句附近的任何地方都会产生归类冲突错误。这是一些复制品:

/*step1 create a table belongs to a contained database and populate some data*/
create  table dbo.test1 (col1 varchar(100),col2 varchar(100))
insert  dbo.test1 values('a','x')
insert  dbo.test1 values('b','y')
insert  dbo.test1 values('c','z')

/*step2 lets see its collation you will see it is correctly as same as its (contained) database */
select name,collation_name from sys.columns where object_name(object_id) = 'test1'

/*step3 reproduce an unpivoted column*/
select * into dbo.test2
from (select * from dbo.test1) a unpivot (val for col in (col1,col2)) a


/*step4 lets check its collation you will see the column specified at "FOR" clause is created as Latin1_General_100_CI_AS_KS_WS_SC */
select name,collation_name from sys.columns where object_name(object_id) = 'test2'

/*step5 make use of the unpivoted table without awareness will cause an error*/
select val + ' = ' + col from dbo.test2 

/*step6 clean up*/
drop table dbo.test1
drop table dbo.test2


您还可以看到有关所包含数据库的文章大多不完整。因此决定使用它需要非常好的即兴表现。