【问题标题】:Do you put your database static data into source-control ? How?您是否将数据库静态数据放入源代码控制中?如何?
【发布时间】:2010-12-04 06:42:02
【问题描述】:

我正在使用带有 Visual Studio 数据库版的 SQL-Server 2008。

使用此设置,保持架构同步非常容易。基本上,有一个“比较架构”工具可以让我将两个数据库的架构和/或一个数据库架构与源代码控制的创建脚本文件夹同步。

但是,在数据方面,情况就不太清楚了,它可以是三种不同的类型:

  • 代码中引用的静态数据。典型示例:我的用户可以更改他们的设置,并且他们的配置存储在服务器上。但是,每个设置都有一个系统范围的默认值,以防用户没有覆盖它。随着更多选项添加到程序中,包含这些默认设置的表会增加。这意味着当签入新功能/选项时,通常还会在数据库中创建系统范围的默认设置。

  • 静态数据。例如。填充下拉列表的产品列表。该程序不依赖于列表中特定产品的存在来工作。例如,这可以是在部署程序的新“unicode 版本”时应在生产中部署的 unicode 编码产品列表。

  • 其他数据,即其他所有数据(日志、用户帐户、用户数据等)

在我看来,我的第三个项目不应该是源代码控制的(当然,它应该定期备份)

但是关于静态数据,我想知道该怎么做。

  • 我应该将插入脚本附加到创建脚本吗?或者可能使用单独的脚本?

  • 我(作为开发人员)如何警告进行部署的人员他们应该执行插入语句?

  • 我应该区分我的两种数据吗? (第一个通常由开发人员创建,而第二个通常由非开发人员创建)

您如何管理您的数据库静态数据?

【问题讨论】:

标签: sql version-control


【解决方案1】:

我已经解释了我在博客Version Control and Your Database 中使用的技术。我使用数据库元数据(在本例中为 SQL Server 扩展属性)来存储部署的应用程序版本。我只有从一个版本升级到另一个版本的脚本。在启动时,应用程序从数据库元数据中读取已部署的版本(缺少元数据被解释为版本 0,即尚未部署任何内容)。对于每个版本,都有一个应用程序功能可以升级到下一个版本。通常这个函数会运行一个内部资源 T-SQL 脚本来执行升级,但也可以是其他的,比如在数据库中部署一个 CLR 程序集。

没有部署“当前”数据库架构的脚本。新的分期付款会遍历所有中间版本,从版本 1 到当前版本。

我喜欢这种技术有几个优点:

  • 对我来说测试新版本很容易。我有以前版本的备份,我应用了升级脚本,然后我可以恢复到以前的版本,更改脚本,再试一次,直到我对结果满意为止。
  • 我的应用程序可以部署在任何以前的版本之上。不同的客户端有不同的部署版本。当他们升级时,我的应用程序支持从任何以前的版本升级。
  • 全新安装和升级没有区别,它们运行相同的代码,因此我需要维护和测试的代码路径更少。
  • DML 和 DDL 更改之间没有区别(您的原始问题)。它们都以相同的方式处理,因为脚本运行以从一个版本更改为下一个版本。当我需要像您描述的那样进行更改(更改默认值)时,我实际上会增加架构版本即使没有发生其他 DDL 更改。所以在 5.1 版本中默认是 'foo',在 5.2 中默认是 'bar' 这是两个版本之间的唯一区别,而“升级”步骤只是一个 UPDATE 语句(如下当然是由版本元数据改变,即 sp_updateextendedproperty)。
  • 所有更改都在源代码控制中,是应用程序源代码的一部分(主要是 T-SQL 脚本)。
  • 我可以轻松访问任何以前的架构版本,例如。重现客户投诉,只需运行升级序列并停止在我感兴趣的版本。

这种方法多次挽救了我的皮肤,我现在是一个真正的信徒。只有一个缺点:在源代码中没有明显的地方可以找到“程序 foo 的当前形式是什么?”。因为最新版本的 foo 可能在 2 或 3 个版本之前已经升级,并且此后没有更改,所以我需要查看 那个 版本的升级脚本。我通常只查看数据库并查看其中的内容,而不是搜索升级脚本。

最后一点:这实际上不是我的发明。这是完全按照 SQL Server 自身升级数据库元数据 (mssqlsystemresource) 的方式建模的。

【讨论】:

    【解决方案2】:

    如果您要更改静态数据(将新项目添加到用于生成下拉列表的表中),则插入应该在源代码管理中并与其余代码一起部署。如果需要插入以使其余代码工作,则尤其如此。否则,在部署代码时可能会忘记这一步,并不会发生那么好的事情。

    如果静态数据来自其他来源(例如美国当前机场代码的导入),那么您可能只需要运行已记录的导入流程。导入过程本身应该在源代码控制中(我们对所有 SSIS 包都这样做),但数据不需要。

    【讨论】:

      【解决方案3】:

      我们最近在 Red Gate 为 SQL 数据比较添加了一项功能,允许将静态数据存储为 DML(每个表一个 .sql 文件)以及 SQL 比较当前支持的模式 DDL。

      要了解其工作原理,here is a diagram 将解释其工作原理。

      这个想法是,当您想要将更改推送到目标服务器时,您可以使用脚本作为源数据源进行比较,从而生成必要的 DML 同步脚本来更新目标。这意味着您不必假设每次都从头开始重新创建目标。我们希望及时在我们即将发布的SQL Source Control tool 中支持静态数据。

      Red Gate Software 产品经理 David Atkinson

      【讨论】:

      • Red Gate 现已发布支持静态数据的 v2。如果不符合您的要求,请试一试并报告给我们。
      • 我正在使用带有 SQL 源代码控制的静态数据功能并取得了一些成功。我的源代码控制指向我的本地文件系统,而我遇到的最大问题是当我进行一些数据更改时,撤消它们很乏味。更改显示在“提交更改”选项卡上,但箭头指向错误的方向 - 它只允许我更新文件。我必须先将其保存到文件中,然后进入源代码管理并撤消这些文件,然后它们将显示在“获取最新”选项卡中,然后我可以将其推回我的数据库。
      • 您是否直接对文件进行更改?我认为支持的方法是更改​​数据,然后将其同步回文件。
      • 你是对的,很抱歉造成混乱。我应该说,“当我在我的数据库中进行数据更改时,撤消它们很乏味。”我在数据库中看到了新的变化,但在那种情况下,我希望箭头指向另一个方向,所以我必须采取变通方法让文件出现在“获取最新”选项卡中(确实有箭头指向另一个方向)。
      • 这可能有效,但如果您从存储库中取消链接并重新链接数据库,则任何更改都可能不明确,因此您可以选择方向。没有保证,但值得一试。
      【解决方案4】:

      我在开发 CMS 系统时遇到过这个问题。

      我将静态数据(代码中引用的内容)附加到数据库创建脚本,然后添加一个单独的脚本来添加任何“初始化数据”(如国家、初始产品数量等)。

      【讨论】:

        【解决方案5】:

        对于前两个步骤,您可以考虑对数据使用中间格式(即 XML),然后使用自制工具或类似 CodeSmith 的工具来生成 SQL,以及可能的源文件,如果(对于例如)您有与代码中使用的枚举相关的查找表 - 这有助于加强一致性。

        这还有一个好处是,如果架构发生变化,在许多情况下,您不必重新生成所有 INSERT 语句 - 您只需更改工具即可。

        【讨论】:

        • 如果您的插入设计正确,则无需更改插入语句,除非您添加了一堆 NOT NULL 列。 XML 是多余的。
        • 我说你可以考虑一下,这通常是矫枉过正,例如我目前的项目不这样做
        【解决方案6】:

        我真的很喜欢你对这三种数据的区分。

        我同意第三个

        在我们的应用程序中,我们尽量避免将数据库放在第一个,因为它是重复的(因为它必须在代码中,所以数据库是重复的)。第二个好处是我们不需要连接或查询即可从代码中访问该值,因此这加快了速度。

        如果我们希望数据库中包含其他信息,例如是否可以根据客户站点进行更改,我们会将两者分开。其他表仍然可以引用该数据(通过索引例如:0、1、2、3 或通过代码例如:EMPTY、SIMPLE、DOUBLE、ALL)。

        对于第二,脚本应该在源代码控制中。我们将它们从结构中分离出来(我认为它们通常会随着时间的推移而被替换,而结构会不断添加增量)。


        我(作为开发人员)如何警告进行部署的人员他们应该执行插入语句?

        我们有一个完整的程序,每个版本都有一个自述文件,脚本等等......

        【讨论】:

        • 根据您使用的设置引擎,您可以添加自定义操作并自动执行此类工作。
        • @Scoregraphic 对不起,我不明白你的信息:-(你能解释一下吗?
        • 如果您使用类似 installshield 的工具,那么该工具应该运行数据库插入脚本。不要把这些事情留给最终用户。
        • @darthcoder 我同意不要求最终用户运行数据库脚本! ;-)
        【解决方案7】:

        首先,我从未使用过 Visual Studio 数据库版。使用此实用程序为您提供的任何工具,您都会得到祝福(或诅咒)。希望这包括很大的灵活性。

        我不知道我会在您的类型 1 和类型 2 静态数据之间产生如此大的差异。两者都是定义一次然后永远不会更新的数据集,除非后续发布和更新,对吧?在这种情况下,主要区别在于数据如何或为何如此,而不是如何存储或初始化。 (除非数据是特定于环境的,如“A”用于开发,“B”用于生产。这将是“类型 4”数据,我将在本文中愉快地忽略它,因为我已经使用 SQLCMD 解决了它变量,它们让我头疼。)

        首先,我会编写一个脚本来创建数据库中的所有表——最好只有一个脚本,否则你可能会有很多脚本(当重命名列变得非常尴尬时,查找和替换)。然后,我将编写一个脚本来填充这些表中的静态数据。该脚本可以附加到表脚本的末尾,或者使其成为自己的脚本,或者甚至为每个表创建一个脚本,如果您有数百或数千行要加载,这是一个好主意。 (有些人制作了一个 csv 文件,然后在其上发出 BULK INSERT,但我会避免这样做,因为它只会为您提供两个文件和一个复杂的过程 [在部署时配置驱动器映射] 来管理。)

        要记住的关键是数据(存储在数据库中)可以并且将会随着时间而改变。很少(如果有的话!)您将有幸删除您的生产数据库,并用一个全新的、闪亮的、新的数据库替换它,该数据库没有过去无数年来所有那些糟糕的数据。数据库都是关于随时间变化的,这就是脚本发挥作用的地方。您从创建数据库的脚本开始,然后随着时间的推移添加脚本以在更改发生时修改数据库——这也适用于您的静态数据(任何类型)。

        (最终,我的方法类似于会计:你有账户,随着变化的到来,你用日记帐分录调整账户。如果你发现你犯了错误,你永远不会回去修改你的条目,你只是一个后续条目来反转和修复它们。这只是一个类比,但逻辑是合理的。)

        【讨论】:

        • 我非常不同意您的“所有内容都在同一个文件中”的立场。我发现每个表(和/或 sp)有一个文件非常方便,这样我就可以使用我的源代码控制工具快速找出两个版本之间发生的变化。一个文件意味着对一个笨拙的长文件进行更多的合并和更多的人眼解析
        • 当然,每个存储过程或函数一个文件——它们确实经常更改,并且非常详细。也可能用于视图和触发器,尽管我们做的很少。但是表并没有太大变化,当它们发生变化时,我不会删除和替换,我会编写一个 ALTER 脚本。考虑到新的外键或基于现有数据填充新列的可能性,需要有某种方法来控制进行更改的顺序。
        【解决方案8】:

        我使用的解决方案是在源代码控制中创建和更改脚本,以及存储在数据库中的版本信息。

        然后,我有一个安装向导,它可以检测是否需要创建或更新数据库 - 更新过程是通过根据数据库中存储的版本信息选择适当的脚本来管理的。

        【讨论】:

        • 那么,您如何将“存储的版本信息”部署到生产数据库? :)
        • 创建和更改脚本设置和维护版本信息。
        【解决方案9】:

        this thread's answer。前两点的静态数据应该在源代码管理中,恕我直言。

        编辑:*新

        • 一体机还是单独的脚本?只要您(开发团队)同意您的部署团队,这并不重要。我更喜欢分隔文件,但我仍然可以始终以正确的顺序创建 all-in-one.sql [Logins, Roles, Users; Tables; Views; Stored Procedures; UDFs; Static Data; (Audit Tables, Audit Triggers)]
        • 你如何确保他们执行它:好吧,让它成为你的应用程序/数据库部署文档中的另一个步骤。如果您推出的应用程序确实需要数据库中的特定(新)静态数据,那么您可能希望在您的应用程序中执行数据库版本检查。作为该脚本的一部分,您将 DB_VERSION 更新为您的新版本号。然后你的应用程序在启动时应该检查它并在需要新的数据库版本时报告错误。
        • 开发和非开发静态数据:我实际上从未见过这种情况。更常见的是真正的静态数据,你可以称之为“dev”,它是主要配置、ISO 静态数据等。另一种是默认查找数据,即用户可以从那里开始,但他们可能会添加更多。插入这些数据的机制可能不同,因为您需要确保不会破坏(强力)用户创建的数据。

        【讨论】:

        • 我读过这个帖子(和这个答案)。我认为“静态数据”这个词太笼统了,值得细化(因此这个问题)
        猜你喜欢
        • 2013-07-03
        • 2010-09-26
        • 1970-01-01
        • 2017-04-20
        • 1970-01-01
        • 2016-12-26
        • 1970-01-01
        • 1970-01-01
        • 2015-06-04
        相关资源
        最近更新 更多