数据库创建脚本 - 外部参数/设置

时间:2010-01-04 17:24:41

标签: sql-server database version-control deployment automation

问题摘要:

是否有比下面发布的方法更好的方法来实现自动部署的数据库创建阶段?

背景/需求:

  • 我正在尝试使用类似于this one的方法开发一致的数据库版本控制流程。这个问题具体是关于基线,其中包括物理创建数据库。

  • 目前的计划是实现一个简单的命令行工具(在.NET中),以应用基线和更改脚本。我希望该工具是通用的(我们有几个独立的事务数据库),因此希望所有脚本都是外部的,包括创建数据库。

  • 测试环境可能不是生产的完美复制品;物理文件的位置和大小可能需要完全不同。

当前的想法:(我正在寻找反馈意见)

基本上是模板系统。在脚本上使用简单的string.Replace,如下所示:

CREATE DATABASE [{DBNAME}] ON PRIMARY
(
    NAME = N'MyDB_Data',
    FILENAME = N'{PRIMARYFILENAME}',
    SIZE = {PRIMARYSIZE}KB,
    MAXSIZE = UNLIMITED,
    FILEGROWTH = 5%
),
FILEGROUP [FG_MyDB_Index]
(
    NAME = N'MyDB_Index',
    FILENAME = N'{INDEXFILENAME}',
    SIZE = {INDEXSIZE}KB,
    MAXSIZE = UNLIMITED,
    FILEGROWTH = 5%
),
-- more filegroups ...
LOG ON 
(
    NAME = N'MyDB_Log',
    FILENAME = N'{LOGFILENAME}',
    SIZE = {LOGSIZE}KB,
    -- etc.
)
GO

ALTER DATABASE [{DBNAME}] SET COMPATIBILITY_LEVEL = 100
GO

-- more ALTER DATABASE stuff ...

显然,要替换的令牌是{DBNAME}{LOGFILESIZE}。这些值可以从命令行参数中获取,也可以从外部文件中获取。

我用这种方法看到的问题:

  • “脚本”将自己称为T-SQL脚本,但实际上是无效的T-SQL。它会强制您使用部署工具或执行繁琐的手动搜索和替换。

  • 无法使用“默认”值运行它。更糟糕的是,它没有提供任何良好的默认值的指示。

  • 感觉很脆弱。看起来有可能以这样一种方式改变脚本:它仍然是有效的SQL(或者至少,它现在是“有效的”),但仍然破坏了部署工具。对于一个人来说,没有任何逃避是令人担忧的。文字字符串中的模板参数使我的皮肤爬行。

我考虑过的其他可能性:

  • 构造一个用sp_executesql执行的动态SQL脚本。这将提供真实参数的好处,而不是一个天真的模板,但会使脚本编写,测试和维护非常麻烦,特别是如果我们决定采用一个新的基线(我们可能 - 它是一个大数据库)

  • 使用SSMS模板参数。这与部署工具很好地分离,但也很难与部署工具集成 - 将其与SSMS联系起来。

  • 将脚本嵌入部署工具中。这样,没有人可以搞乱它,而且很明显,脚本只是一个必须处理的模板。默认值可以嵌入到“接近”脚本的某个位置。主要的缺点是部署工具变得特定于应用程序,并且可能需要对不需要更改代码的内容进行代码更改。

  • 从外部的人类可读文件(如YAML)动态生成整个脚本。起初这个想法似乎非常优雅,但最终它开始下沉,我可能会重新发明轮子。关于数据库的 Everything 必须包含在文件中,这是否真的比手动修改普通的SQL脚本甚至通过SSMS手动创建数据库有任何优势?

    < / LI>

这些选项似乎都不对。我想要的是独立的东西(就像代码在理论上独立于你用来构建它的环境一样),而且可读(没有“SQL中的SQL”),并且不言自明(清楚地标识出需要什么设置以及可能有什么好的默认设置)。

是否有任何方法可以实现我想要实现的一切?或者我只是过于挑剔或以错误的方式看待问题?

(P.S。我目前正在寻找能够为我执行此任务的商业,独立,第三方工具。“现在我有两个问题。”)

3 个答案:

答案 0 :(得分:1)

我可能会将此脚本用作命令行工具中的嵌入式模板;获取所需的最少信息(替换占位符 - DBName和LogFileSize;可以从命令行参数中从DBName推导出其他文件组名称,例如主文件组的FG_ {DBName} _PRIMARY)。使用文本搜索/替换来填充空白,然后针对要将其部署到的SQL Server执行此操作。

E.g。类似的东西:

CreateDB -server:(local) -dbname:MyTestDB -logsize:50 (as in 50 MB)

或:使用SMO(SQL Server管理对象)来创建数据库。您基本上需要相同的信息(数据库名称,日志文件大小),您可以以编程方式创建数据库及其布局 - 无需T-SQL脚本。

作为旁注:如果您要创建单独的文件组,我建议至少使用此布局:

  • 主要文件组:仅用于系统目录视图 - 没有别的
  • 数据文件组:标记为DEFAULT,用于表格
  • INDEX文件组:索引

这样,您可以最小化主文件组的大小,从而最大程度地降低它遇到磁盘错误并受到损坏的风险。主文件组包含系统目录,因此如果该FG被破坏,则整个数据库都是吐司。

答案 1 :(得分:1)

您是否考虑过使用SQLCMD scriptsSQLCMD utility而不是编写自己的命令行界面,或者编写自己的命令并简单地包装SQLCMD功能?当然,这将假设您只想支持SQL 2005及更高版本。我在过去通过几种不同的方式完成了这项工作(即使用包含SQLCMD的params / options的简单批处理文件,使用包含代码的更广泛的方法,不幸的是当时的VB 6.0,等等) 。

如果你采用自己的代码包装路线,可能也想考虑利用powershell(我现在也在考虑这个问题)。 Sql Server现在包括自定义Powershell提供程序和扩展,用于SMO功能,代码执行,管理等,可以自然而轻松地扩展以包装SQLCMD和SQL功能。

鉴于您正在尝试做什么,SQLCMD(和SQLCMD脚本)的好处似乎很适合:

  • 脚本仍然可以使用/解释/与SSMS和其他IDE的集成
  • 默认值有几个选项,但没有真正集成到脚本本身(环境变量,命令行选项等)。此外,您可能需要考虑从运行的服务器/实例上的预定义位置(例如model或master或tempdb)中提取文件/组位置的默认值。
  • 当前支持SQLCMD的IDE会在SQLCMD模式下为未定义的变量/值组合抛出异常,从而不那么脆弱

如果你想交换关于你的项目的笔记/想法,我肯定会帮助编写代码和/或只是讨论我遇到的一些挑战(例如引擎的不同版本和功能使用是我最初没想过的一些事情。)

答案 2 :(得分:1)

我们通过制作可以使用sqlcmd参数的脚本解决了类似的问题。类似的东西:

:setvar filename somefile.ext
:setvar version 1
:on error exit

print 'This is version $(version) on $(filename)'
-- the rest of the actual script

这可以通过命令行或SSMS运行。最终我们制作了一个可以读取文件并用相同语法替换变量的工具。

我不认为它会照顾你列出的每一个问题,但它应该有所帮助。