使用DacFx部署DACPAC时随机出现变更跟踪启用错误
SSDT DACPAC部署中变更跟踪的随机错误问题及疑问
项目配置
我们维护一个基于SQL Server Data Tools (SSDT)的Visual Studio数据库项目,通过DacFx结合PowerShell脚本部署生成的DACPAC包,项目中已启用两类变更跟踪:
- 数据库级变更跟踪:通过项目设置开启,对应项目配置代码:
<IsChangeTrackingOn>True</IsChangeTrackingOn> - 表级变更跟踪:通过
ALTER TABLE语句开启,示例代码:ALTER TABLE [TableName] ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = OFF);
初始问题现象
部署过程中随机出现以下错误:
必须先在数据库上启用变更跟踪,才能在表上启用它。
该错误表明,表级的ALTER TABLE变更有时会在数据库级变更跟踪设置生效前执行。
尝试的缓解方案及新问题
为解决上述问题,我们添加了预部署脚本,显式检查并启用数据库级变更跟踪:
IF NOT EXISTS ( SELECT 1 FROM sys.change_tracking_databases WHERE database_id = DB_ID() ) BEGIN ALTER DATABASE CURRENT SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON); END
但添加脚本后,偶尔会在预部署阶段出现另一个随机错误:
数据库已启用变更跟踪。
脚本中明明做了存在性检查,说明部分执行场景下,项目级的变更跟踪设置先于预部署脚本执行,提前启用了变更跟踪,怀疑是并行执行导致顺序混乱。
约束条件
我们无法通过以下方式解决问题:
- 移除项目级变更跟踪设置:否则SSDT部署会自动尝试禁用变更跟踪,回到初始错误
- 将变更跟踪启用逻辑移至部署后脚本:SSDT部署流程会先禁用变更跟踪,部署后再启用会丢失现有变更跟踪数据
最终调整的预部署脚本
基于上述约束,我们修改预部署脚本,通过异常捕获优雅处理冲突:
BEGIN TRY IF NOT EXISTS ( SELECT 1 FROM sys.change_tracking_databases WHERE database_id = DB_ID() ) BEGIN ALTER DATABASE CURRENT SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON); END END TRY BEGIN CATCH PRINT 'Change Tracking is already enabled in this database.'; END CATCH
观察结果
- 我们通过Azure Durable Function的扇出模式,使用DacFx批量部署DACPAC到多个数据库
- 部分环境中,无论是否使用预部署脚本,部署都能正常完成
- 当部署为单线程且严格按以下顺序执行时,不会出现任何问题:
- 执行预部署脚本
- 应用SSDT项目的数据库级设置
- 部署表、视图、存储过程等SSDT对象
- 执行部署后脚本
核心疑问
- 这种随机错误是否由服务器的并行执行或MaxDOP设置导致?
- 是否可以在不修改服务器级配置的前提下,控制DACPAC部署时的MaxDOP(或强制单线程执行)?
- 导致该随机错误的根本原因是什么?
内容的提问来源于stack exchange,提问作者Indi
相关产品推荐
相关产品推荐

