我正处于研究阶段,试图在现有的一个小项目上采用2012年的数据库项目.我是C#开发人员,不是DBA,所以我对最佳实践不是特别熟练.我已经搜索google和stackoverflow几个小时了,但我仍然不知道如何正确处理一些关键的部署场景.

1) 在几个开发周期中,我如何管理数据库的多个版本?如果我的数据库v3上有一个客户端,我想将其升级到v8,我该如何管理它?我们目前为我们产品的每个版本管理手工制作的模式和数据迁移脚本.我们是否仍然需要单独做这件事,或者在新的范式中有什么东西支持或取代这一点?

2) 如果模式发生变化,需要移动数据,那么最好的处理方法是什么?我假设在部署前脚本中进行了一些工作来保存数据,然后部署后脚本将其放回正确的位置.是这样还是有更好的办法?

3) 对于如何最好地使用这些新技术的任何其他建议或指导,我们也非常感谢!

UPDATE:.自从我最初提出这个问题以来,我对这个问题的理解有了一点提高,虽然我提出了一个可行的解决方案,但它并不是我所希望的解决方案.下面是对我问题的重新描述:

我遇到的问题纯粹与数据有关.如果我的应用程序版本1上有一个客户机,并且我想将其升级到应用程序版本5,那么如果他们的数据库没有数据,我这样做不会有问题.我只需要让SSDT智能地比较模式,并一次性迁移数据库.不幸的是,客户有数据,所以它不是那么简单.模式从我的应用程序的版本1更改为版本2,再更改为版本3(等等),所有影响数据.我目前的数据管理策略要求我 for each 版本升级(1到2、2到3等)维护一个脚本.这使我无法直接从应用程序的版本1升级到版本5,因为我没有数据迁移脚本. for each 客户端创建自定义升级脚本,或者管理从每个版本到每个更高版本的升级脚本的前景是无法管理的.我希望SSDT能够实现某种策略,使管理数据方面的事情变得更容易,甚至可能与管理模式方面的事情一样容易.我最近在SSDT的经历并没有给我带来任何希望,但我很想找到不同的方法.

推荐答案

我自己也在做这件事,我可以告诉你这并不容易.

首先,回答JT的回复——你不能忽略"版本",即使SSDT有声明式更新机制.SSDT在将任何源模式移动到任何目标模式方面做了一项"相当不错"的工作(前提是你知道所有的switch 和trap ),这确实不需要验证本身,但它不知道如何管理"数据移动"(至少我看不到!).所以,就像DBProj一样,您可以在Pre/Post脚本中使用自己的设备.由于数据运动脚本依赖于已知的开始和结束模式状态,因此无法避免对数据库进行版本控制.因此,"数据运动"脚本必须应用于模式的版本化快照,这意味着您不能随意将DB从v1更新到v8,并期望数据运动脚本v2到v8正常工作(想必,您不需要v1数据运动脚本).

遗憾的是,在SSDT发布中,我看不到任何机制允许我以集成的方式处理这种情况.这意味着你必须加入自己的骗局.

第一个技巧是跟踪数据库(和SSDT项目)中的版本.我开始在DBProj中使用一个技巧,并将其带到SSDT,在做了一些研究之后,发现其他人也在使用这个技巧.您可以将DB扩展属性应用于数据库本身(称之为"BuildVersion"或"AppVersion"之类),并将版本值应用于它.然后,您可以在SSDT项目本身中捕获此扩展属性,SSDT将其作为脚本添加(然后可以选中包含扩展属性的发布选项).然后,我使用SQLCMD变量来标识当前过程中应用的源和目标版本.一旦确定了源(项目快照)和目标(即将更新的目标数据库)之间的版本增量,就可以找到需要应用的所有快照.不幸的是,从SSDT部署开始,这是很难做到的,您可能必须将其转移到构建或部署管道(我们使用TFS自动部署,并有自定义操作来实现这一点).

下一个障碍是保留模式的快照及其关联的数据运动脚本.在这种情况下,它有助于使脚本尽可能幂等(这意味着,您可以重新运行脚本,而不会产生任何不良副作用).它有助于从只能执行一次的脚本中分离可以安全地重新运行的脚本.对于静态引用数据(字典或查找表),我们也在做同样的事情——换句话说,我们有一个合并脚本库(每个表一个),用于保持引用数据同步,这些脚本包含在部署后脚本中(通过SQLCMD:r命令).这里需要注意的重要一点是,如果这些引用表中的任何一个相互之间有FK引用,那么您可以按照正确的顺序执行它们.我们将它们按顺序包含在主部署后脚本中,这有助于我们创建一个工具来为我们生成这些脚本——它还解析依赖顺序.我们在"版本"结束时运行这个生成工具,以捕获静态参考数据的当前状态.所有其他数据运动脚本基本上都是特例,很可能只会一次性使用.在这种情况下,可以执行以下两种操作之一:可以对db build/app版本使用IF语句,或者可以在创建每个快照包后删除1次脚本.

请记住,SSDT将禁用FK判断约束,并仅在部署后脚本运行后重新启用它们.例如,这使您有机会填充新的非空字段(顺便说一句,您必须启用该选项为非空列生成临时"智能"默认值,以使其工作).但是,FK判断约束仅对SSDT由于架构更改而正在重新创建的表禁用.对于其他情况,您有责任确保数据运动脚本以正确的顺序运行,以避免判断约束投诉(或者手动在脚本中禁用/重新启用它们).

DACPAC可以帮助您,因为DACPAC本质上是一个快照.它将包含多个描述模式的XML文件(类似于项目的构建输出),但在创建模式时被冻结.然后可以使用SQLPACKAGE.EXE或部署提供程序来发布该包快照.我还没有完全弄清楚如何使用DACPAC版本控制,因为它更多地与"已注册"的数据应用程序相关联,所以我们只能使用自己的版本控制方案,但我们确实将自己的版本信息放入了DACPAC文件名中.

我希望我能提供一个更具结论性和详尽的例子,但我们仍在解决这些问题.

SSDT真正糟糕的一点是,与DBProj不同,它目前不可扩展.尽管它在很多方面都比DBProj做得好,但除非在pre/post脚本中找到解决问题的方法,否则无法覆盖其默认行为.我们现在试图解决的问题之一是,当你有数千万条记录时,重新创建更新表(CCDR)的默认方法真的很糟糕.

-更新:我已经有一段时间没看到这篇文章了,但它最近很活跃,所以我想我应该补充几点重要的注意事项:如果你使用的是VS2012,2013年6月发布的SSDT现在内置了一个数据比较工具,还提供了可扩展性点——也就是说,现在,您可以为项目包含构建贡献者和部署计划修饰符.

Sql相关问答推荐

帮助修复查询以识别SQL DW中数据中的递归关系

如果开始期间不存在PostgresSql回填数据

仅在特定字符串之后提取两个圆括号之间的计量单位文本

不同表达方式时的大小写

如何在SQL中更新Json字符串

如何计算一个用户S的日常连胜?

为什么我的SQL标量函数有时会抛出";子查询返回多个值.这是不允许的.

如何为该查询编写正确分区依据

Netezza SQL:判断两个表是否相同

不同计数的 Postgres PIVOT 表

Grafana SQL 模板变量(值、文本)

对现有记录进行分组

除了风格之外,还有什么理由更喜欢简单的CASE WHEN而不是搜索呢?

JSON_VALUE 不适用于提取的 json 中的嵌套路径

计算 ID 满足条件的次数

计算 BigQuery 中列的中值差 - 分析函数不能作为聚合函数的参数

SQL中如何转置表格 UNPIVOT是唯一的 Select 吗?

带聚合函数的 percentile_cont

插入行时的行安全策略问题

如何在 SQL Server 中将 -13422.8450 舍入到 -13422.84