关于数据库对象是否应该受版本控制的SO社区维基进行了一些讨论 . 但是, I haven't seen much discussion about the best-practices for creating a build-automation process for database objects.
这对我的团队来说是一个有争议的讨论点 - 特别是在评估数据库部署自动化方法的好处和风险时,开发人员和DBA经常有不同的目标,方法和关注点 .
I would like to hear some ideas from the SO community about what practices have been effective in the real world.
我意识到这有点主观,哪些实践真的是最好的,但我认为一个关于哪些工作可能对许多人有帮助的良好对话 .
Here are some of my teaser questions about areas of concern in this topic. These are not meant to be a definitive list - rather a starting point for people to help understand what I'm looking for.
-
测试和 生产环境 环境是否应该从源代码控制构建?
-
两者都应该使用自动化构建 - 还是应该通过从稳定的,最终的测试环境中复制对象来构建 生产环境 ?
-
如何处理部署脚本中测试和 生产环境 环境之间的潜在差异?
-
如何测试部署脚本是否与测试中的 生产环境 一样有效?
-
哪些类型的对象应该受版本控制?
-
只是代码(程序,包,触发器,java等)?
-
索引?
-
约束?
-
表定义?
-
表变更脚本? (例如,ALTER脚本)
-
一切?
-
哪些类型的对象不应受版本控制?
-
序列?
-
拨款?
-
用户帐户?
-
如何在SCM存储库中组织数据库对象?
-
如何处理转换脚本或ALTER脚本等一次性事务?
-
如何处理退出数据库中的对象?
-
谁应该负责将对象从开发推广到测试级别?
-
如何协调多个开发人员的更改?
-
如何处理多个系统使用的数据库对象的分支?
-
对此流程可以合理地做出哪些例外(如果有的话)?
-
安全问题?
-
具有去识别问题的数据?
-
无法完全自动化的脚本?
-
如何使流程具有弹性和可执行性?
-
开发者错误?
-
出乎意料的环境问题?
-
用于灾难恢复?
-
您如何让决策者相信DB-SCM的好处真正证明了成本的合理性?
-
轶事证据?
-
行业研究?
-
行业最佳实践建议?
-
向公认的当局上诉?
-
成本/效益分析?
-
谁应该"own"这个模型中的数据库对象?
-
开发人员?
-
DBA?
-
数据分析师?
-
不止一个?
11 回答
以下是您的问题的一些答案:
测试和 生产环境 环境是否应该从源代码控制构建? YES
两者都应该使用自动化构建 - 还是应该通过从稳定的,最终的测试环境中复制对象来构建 生产环境 ?
Automation for both. Do NOT copy data between the environments
如何处理部署脚本中测试和 生产环境 环境之间的潜在差异?
Use templates, so that actually you would produce different set of scripts for each environment (ex. references to external systems, linked databases, etc)
如何测试部署脚本是否与测试中的 生产环境 一样有效?
You test them on pre-production environment: test deployment on exact copy of production environment (database and potentially other systems)
哪些类型的对象应该受版本控制?
只是代码(程序,包,触发器,java等)?
索引?
约束?
表定义?
表变更脚本? (例如,ALTER脚本)
一切?
Everything, and:
Do not forget static data (lookup lists etc), so you do not need to copy ANY data between environments
Keep only current version of the database scripts (version controlled, of course), and
Store ALTER scripts: 1 BIG script (or directory of scripts named liked 001_AlterXXX.sql, so that running them in natural sort order will upgrade from version A to B)
哪些类型的对象不应受版本控制?
序列?
拨款?
用户帐户?
see 2. If your users/roles (or technical user names) are different between environments, you can still script them using templates (see 1.)
如何在SCM存储库中组织数据库对象?
如何处理转换脚本或ALTER脚本等一次性事务?
see 2.
如何处理退出数据库中的对象?
deleted from DB, removed from source control trunk/tip
谁应该负责将对象从开发推广到测试级别?
dev/test/release schedule
如何协调多个开发人员的更改?
try NOT to create a separate database for each developer. you use source-control, right? in this case developers change the database and check-in the scripts. to be completely safe, re-create the database from the scripts during nightly build
如何处理多个系统使用的数据库对象的分支?
tough one: try to avoid at all costs.
对此流程可以合理地做出哪些例外(如果有的话)?
安全问题?
do not store passwords for test/prod. you may allow it for dev, especially if you have automated daily/nightly DB rebuilds
具有去识别问题的数据?
无法完全自动化的脚本?
document and store with the release info/ALTER script
如何使流程具有弹性和可执行性?
开发者错误?
tested with daily build from scratch, and compare the results to the incremental upgrade (from version A to B using ALTER). compare both resulting schema and static data
出乎意料的环境问题?
use version control and backups
compare the PROD database schema to what you think it is, especially before deployment. SuperDuperCool DBA may have fixed a bug that was never in your ticket system :)
用于灾难恢复?
您如何让决策者相信DB-SCM的好处真正证明了成本的合理性?
轶事证据?
行业研究?
行业最佳实践建议?
向公认的当局上诉?
成本/效益分析?
if developers and DBAs agree, you do not need to convince anyone, I think (Unless you need money to buy a software like a dbGhost for MSSQL)
谁应该"own"此模型中的数据库对象?
开发人员?
DBA?
数据分析师?
不止一个?
Usually DBAs approve the model (before check-in or after as part of code review). They definitely own performance related objects. But in general the team own it [and employer, of course :)]
I treat the SQL as source-code when possible
如果我可以在 standard's compliant SQL 中编写它,那么它通常会在我的源代码管理中的文件中 . 该文件将尽可能多地定义,例如SP,表CREATE语句 .
我还包括用于源代码管理测试的虚拟数据:
proj / sql / setup_db.sql
proj / sql / dummy_data.sql
proj / sql / mssql_specific.sql
proj / sql / mysql_specific.sql
然后我抽象出所有的SQL查询,以便我可以为MySQL,Oracle,MSSQL或其他任何东西构建整个项目 .
构建和测试自动化使用这些构建脚本作为 they are as important as the app source 并测试从完整性到触发器,过程和日志记录的所有内容 .
我们通过TeamCity使用持续集成 . 在每次签入源代码控制时,从头开始重新构建数据库和所有测试数据,然后是代码,然后针对代码运行单元测试 . 如果您正在使用像CodeSmith这样的代码生成工具,它也可以放入您的构建过程中,以便在每次构建时生成新的数据访问层,确保所有层“匹配”并且不会因为SP参数不匹配或缺少列 .
每个构建都有自己的SQL脚本集合,这些脚本存储在源代码管理的$ project \ SQL \目录中,分配了一个数字前缀并按顺序执行 . 这样,我们就会在每次构建时练习我们的部署过程 .
根据查找表,我们的大多数查找值也存储在脚本中并运行以确保配置数据符合我们的预期,例如“reason_codes”或“country_codes” . 通过这种方式,我们可以在开发中进行查找数据更改,测试它,然后通过QA和 生产环境 “提升”它,而不是使用工具来修改 生产环境 中的查找值,这对正常运行时间来说是危险的 .
我们还创建了一组“回滚”脚本来撤消我们的数据库更改,以防 生产环境 构建变得棘手 . 您可以通过运行它们来测试回滚脚本,然后在部署脚本运行后重新运行低于您的版本的单元测试 .
1 for Liquibase :LiquiBase是一个开源(LGPL),独立于数据库的库,用于跟踪,管理和应用数据库更改 . 它 Build 在一个简单的前提上:所有数据库更改(结构和数据)都以基于XML的描述方式存储,并检入源代码管理 . 好的一点是,DML更改是在语义上存储的,而不仅仅是diff,因此您可以跟踪更改的目的 .
它可以与GIT版本控制相结合,以实现更好的交互 . 我将配置我们的dev-prod环境来试用它 .
您还可以使用Maven,Ant构建系统从脚本构建 生产环境 代码 .
减去的是LiquiBase没有集成到广泛的SQL IDE中,你应该自己做基本的操作 .
除此之外,您可以使用DBUnit进行数据库测试 - 此工具允许使用数据生成脚本来测试您的 生产环境 环境并进行清理 .
恕我直言:
将DML存储在文件中,以便您可以对它们进行版本控制 .
从源代码管理自动化架构构建过程 .
出于测试目的,开发人员可以使用从源代码控制构建的本地数据库,通过构建系统负载测试使用脚本或DBUnit脚本(来自源代码管理)进行数据 .
LiquiBase允许您提供"run sequence"脚本以尊重依赖性 .
应该有DBA团队在 生产环境 使用之前用所有更改检查主早午餐 . 我的意思是他们在进入MASTER主干之前检查来自其他DBA的主干/分支 . 因此,主人始终保持一致并准备好 生产环境 .
我们在计费 生产环境 数据库中遇到了所有提到的代码更改,合并和重写问题 . 这个主题非常适合发现所有这些内容 .
通过询问"teaser questions",你似乎对某个讨论更感兴趣,而不是某人对最终答案的看法 . 活跃的(> 2500名成员)邮件列表agileDatabases解决了许多这些问题,根据我的经验,这是一个用于此类讨论的复杂而民用的论坛 .
我基本同意van给出的每个答案 . 更深入的了解,我的数据库管理基准是K. Scott Allen series(必读,恕我直言 . 而且Jeff's opinion似乎也是如此) .
数据库对象总是可以通过启动单个SQL文件(它本身可以调用其他SQL文件)从头开始重建:
Create.sql
. 这可以包括静态数据插入(列表......) .SQL脚本已参数化,因此不会在纯文件中存储依赖于环境的和/或敏感信息 .
我使用自定义批处理文件来启动
Create.sql
:Create.cmd
. 它的目标主要是检查先决条件(工具,环境变量......)并将参数发送到SQL脚本 . 它还可以批量加载CSV文件中的静态数据以提高性能的问题 .通常,系统用户凭据将作为参数传递给
Create.cmd
文件 .恕我直言,动态数据加载应该需要另一个步骤,具体取决于您的环境 . 开发人员希望根据测试,垃圾或无数据加载他们的数据库,而在另一端, 生产环境 经理将希望加载 生产环境 数据 . 我也会考虑将测试数据存储在源代码控制中(例如,简化单元测试) .
一旦数据库的第一个版本投入 生产环境 ,您不仅需要构建脚本(主要用于开发人员),还需要升级脚本(基于相同的原则):
必须有一种从数据库中检索版本的方法(我使用存储过程,但表也可以) .
在发布新版本之前,我创建了一个
Upgrade.sql
文件(可以调用其他版本),允许将版本N-1升级到版本N(N是正在发布的版本) . 我将此脚本存储在名为N-1
的文件夹下 .我有一个进行升级的批处理文件:
Upgrade.cmd
. 它可以通过简单的SELECT语句检索数据库的当前版本(CV),启动存储在CV
文件夹下的Upgrade.sql
脚本,然后循环直到找不到文件夹 . 这样,您可以自动从N-3升级到N.这个问题是:
很难自动比较数据库模式,具体取决于数据库供应商 . 这可能导致升级脚本不完整 .
对 生产环境 环境的每次更改(通常由DBA进行性能调整)也应该找到源代码控制的方式 . 为了确保这一点,通常可以通过触发器记录对数据库的每个修改 . 每次升级后都会重置此日志 .
更理想的是,DBA发起的更改应尽可能是发布/升级过程的一部分 .
至于您希望在源代码管理下拥有哪种数据库对象?好吧,我会尽可能多地说,但不是更多;-)如果你想用密码创建用户,给他们一个默认密码(登录/登录,实用于单元测试目的),并使密码更改为手动操作 . 这种情况在Oracle中发生很多,其中模式也是用户......
我们在Git版本控制中使用带有MSSQL数据库的Silverlight项目 . 最简单的方法是确保你有一个精简的数据库(内容明智),并从f.e.做一个完整的转储 . 视觉工作室 . 然后,您可以从构建脚本执行'sqlcmd',以在每台开发计算机上重新创建数据库 .
对于部署,这是不可能的,因为数据库太大:这是将它们放在数据库中的主要原因 .
我坚信DB应该是源代码控制的一部分,并且在很大程度上是构建过程的一部分 . 如果它在源代码控制中,那么在SQL中编写存储过程时,我就像在C#中编写类时一样,具有相同的编码安全保护 . 我通过在源代码树下包含一个DB脚本目录来完成此操作 . 此脚本目录不一定有一个文件用于数据库中的一个对象 . 这对屁股来说会很痛苦!我在我的数据库中开发了一个我想在我的代码项目中 . 然后,当我准备签入时,我在我的数据库的最后一个版本和我正在处理的当前版本之间做了一个差异 . 我使用SQL Compare来生成所有更改的脚本 . 然后将此脚本保存到我的db_update目录,其中包含特定的命名约定1234_TasksCompletedInThisIteration,其中该数字是已存在的脚本集中的下一个数字,名称描述了此检查中正在执行的操作 . 我这样做是因为as我的构建过程的一部分,我从一个新的数据库开始,然后使用此目录中的脚本以编程方式构建 . 我编写了一个自定义的NAnt任务,它遍历每个脚本在裸db上执行其内容 . 显然,如果我需要一些数据进入数据库,那么我也有数据插入脚本 . 这也有很多好处 . 一,我的所有东西都是版本的 . 二,每个构建都是一个新构建,这意味着不会有任何偷偷摸摸的东西进入我的开发过程(例如导致系统奇怪的脏数据) . 三,当一个新人被添加到开发团队时,他们只需要获得最新信息,他们的本地开发人员即可为他们构建 . 四,我可以在我的数据库上运行测试用例(我没有把它称为“单元测试”!),因为每次构建都会重置数据库的状态(这意味着我可以测试我的存储库而不必担心将测试数据添加到D b) .
这不适合所有人 .
这不适用于每个项目 . 我经常从事绿色领域项目,这让我很方便!
而不是进入白塔争论,这是一个解决方案,对我来说在现实世界问题上非常有效 .
从头开始构建数据库可以概括为管理sql脚本 .
DBdeploy 是一个检查当前状态的工具数据库 - 例如以前运行过哪些脚本,可以运行哪些脚本,因此需要运行哪些脚本 .
然后它会将所有需要的脚本整理在一起并运行它们 . 然后它记录已运行的脚本 .
它不是最漂亮的工具或最复杂的工具 - 但通过精心管理,它可以很好地工作 . 它是开源的,易于扩展 . 一旦很好地处理了脚本的运行,就可以轻松地添加一些额外的组件,例如shell脚本,它可以检查最新的脚本并针对特定实例运行dbdeploy .
在这里看一个很好的介绍:
http://code.google.com/p/dbdeploy/wiki/GettingStarted
你可能会发现Liquibase处理了很多你正在寻找的东西 .
每个开发人员都应该拥有自己的本地数据库,并使用源代码控制来发布给团队 . 我的解决方案在这里:http://dbsourcetools.codeplex.com/玩得开心, - 弥敦道