在某些情况下,SqlPackage 操作会花费比预期更长的时间或无法完成。 本文介绍一些常见的建议策略,用于排查这些操作的性能问题或提高性能。 建议阅读每个操作的特定文档页以了解可用的参数和属性,可以将本文作为切入点来调查 SqlPackage 操作。
总体策略
一般来说,通过 SqlPackage 的 .NET 版本可以获得更好的性能,而不是通过 DacFramework.msi 安装的 .NET Framework 版本。
如果你无法安装 SqlPackage dotnet 工具,它可以让你在任何目录的命令提示符中执行 SqlPackage 命令:
- 下载适用于所用操作系统(Windows、macOS 或 Linux)的 .NET 8 版 SqlPackage 的 zip。
- 按照下载页面上的指示解压存档。
- 打开命令提示符,将目录 (
cd) 更改为 SqlPackage 文件夹。
使用最新版本的 SqlPackage,性能改进和错误修复会定期发布。
使用 SqlPackage 替换导入/导出服务
如果尝试使用导入/导出服务导入或导出数据库,则可以使用 SqlPackage 执行相同的操作,并对可选参数和属性进行更多控制。
优化 BACPAC 导入 - SqlPackage Done Right! 的博客文章介绍了使用 SqlPackage 而不是导入/导出服务.bacpac的步骤。
若要导入,示例命令为:
./SqlPackage /Action:Import /sf:<source-bacpac-file-path> /tsn:<full-target-server-name> /tdn:<a new or empty database> /tu:<target-server-username> /tp:<target-server-password> /df:<log-file>
若要导出,示例命令为:
./SqlPackage /Action:Export /tf:<target-bacpac-file-path> /ssn:<full-source-server-name> /sdn:<source-database-name> /su:<source-server-username> /sp:<source-server-password> /df:<log-file>
使用多因素认证作为用户名和密码的替代方案,使用Microsoft Entra认证。 将 /ua:true 和 /tid:"contoso.onmicrosoft.com" 替换为用户名和密码参数。
Diagnostics
诊断日志和诊断包支持诊断 SqlPackage 中的错误和意外行为。 诊断日志对于故障排除至关重要,并通过 /DiagnosticsFile:<filename> 参数捕获到文件中。
通过参数 /DiagnosticsLevel 控制诊断输出的细节水平。 使用 Information 和 Verbose 值获取更多细节。
在运行 SqlPackage 前,通过设置 DACFX_PERF_TRACE=true 环境变量来记录与性能相关的跟踪数据。 跟踪数据会增加日志输出,因此仅在诊断性能问题时包含。 若要在 PowerShell 中设置此环境变量,请使用以下命令:
Set-Item -Path Env:DACFX_PERF_TRACE -Value true
在 SqlPackage 162.5 及以后版本中,你可以生成诊断包来帮助排查故障。 诊断包包含 SqlPackage 版本、执行的命令、有关源数据库模型和目标数据库模型的信息以及命令的输出。 要生成诊断包,请使用 /DiagnosticsPackageFile:<filename> 参数。
常见问题
超时错误
对于超时问题,请使用以下属性来调优 SqlPackage 与 SQL 实例之间的连接:
-
/p:CommandTimeout=: 指定查询运行时的命令超时(秒数)。 默认值:60 -
/p:DatabaseLockTimeout=:指定数据库锁定超时(以秒为单位)。 使用-1表示无限期等待。 默认值:60 -
/p:LongRunningCommandTimeout=:指定长时间运行命令的超时时间(以秒为单位)。 默认值0会无限期等待。
客户端资源消耗
对于导出和提取命令,SqlPackage 会将表数据传递到临时目录以缓冲,然后再写入 BACPAC 或 DACPAC 文件。 这种存储需求可能会很大,具体取决于待导出数据的总大小。 使用属性 /p:TempDirectoryForTableData=<path> 指定备用临时目录。
SqlPackage 在内存中编译模式模型。 对于大型数据库模式,运行 SqlPackage 的客户端机器的内存需求可能相当可观。
服务器资源消耗低
默认情况下,SqlPackage 将最大服务器并行度设置为 8。 如果你发现服务器资源消耗低,提高参数值 MaxParallelism 可以提升性能。
访问令牌
使用 /AccessToken: or /at: 参数可以实现基于令牌的SqlPackage认证,但将令牌传递给命令时可能比较棘手。 如果你在 PowerShell 中解析访问令牌对象,要么显式传递字符串值,要么将令牌属性的引用包裹在 $()。 例如:
$Account = Connect-AzAccount -ServicePrincipal -Tenant $Tenant -Credential $Credential
$AccessToken_Object = (Get-AzAccessToken -Account $Account -Resource "https://database.windows.net/")
$AccessToken = $AccessToken_Object.Token
SqlPackage /at:$AccessToken
# OR
SqlPackage /at:$($AccessToken_Object.Token)
Connection
如果无法连接 SqlPackage,可能是服务器未启用加密,或者配置的证书可能不是由受信任的证书颁发机构颁发(如自签名证书)。 可以将 SqlPackage 命令更改为在不加密的情况下连接或信任服务器证书。 最佳做法是确保可以与服务器建立受信任的加密连接。
- 在没有加密的情况下进行连接:
/SourceEncryptConnection:False或/TargetEncryptConnection:False - 信任服务器证书:
/SourceTrustServerCertificate:True或/TargetTrustServerCertificate:True
连接SQL实例时,你可能会看到以下一个或多个警告信息,表明命令行参数可能需要更改才能连接到服务器:
The settings for connection encryption or server certificate trust may lead to connection failure if the server is not properly configured.
The connection string provided contains encryption settings which may lead to connection failure if the server is not properly configured.
有关 SqlPackage 中连接安全更改的详细信息,请参阅 SqlPackage 161 中的连接安全改进。
约束的导入操作错误 2714
当你执行导入操作时,如果某个对象已经存在,你可能会收到错误2714:
*** Error importing database:Could not import package.
Error SQL72014: Core Microsoft SqlClient Data Provider: Msg 2714, Level 16, State 5, Line 1 There is already an object named 'DF_Department_ModifiedDate_0FF0B724' in the database.
Error SQL72045: Script execution error. The executed script:
ALTER TABLE [HumanResources].[Department]
ADD CONSTRAINT [DF_Department_ModifiedDate_] DEFAULT ('') FOR [ModifiedDate];
以下是此错误的原因和解决方法:
- 验证要导入到的位置是否为空数据库。
- 如果你的数据库有使用属性
DEFAULT(SQL Server为约束分配随机名称)和显式命名约束的约束,同名约束可能会被创建两次。 使用所有显式命名的约束(不使用DEFAULT),或使用所有系统定义的名称(使用DEFAULT)。 - 手动编辑
model.xml文件,并将导致错误的名称重新命名约束,使其名称为唯一。 只有在 Microsoft 支持的指示下进行,并且有.bacpac损坏风险时,才应执行此选项。
堆栈溢出异常
包含大量嵌套语句的大型 T-SQL 脚本可能导致间歇性或持续性的堆栈溢出异常。 当出现这种情况时,错误消息会包含文本 Stack overflow 和栈跟踪:
Microsoft.SqlServer.TransactSql.ScriptDom.TSqlFragmentVisitor.Visit(Microsoft.SqlServer.TransactSql.ScriptDom.BinaryQueryExpression)
Microsoft.SqlServer.TransactSql.ScriptDom.TSqlFragmentVisitor.ExplicitVisit(Microsoft.SqlServer.TransactSql.ScriptDom.BinaryQueryExpression)
Microsoft.SqlServer.TransactSql.ScriptDom.BinaryQueryExpression.Accept(Microsoft.SqlServer.TransactSql.ScriptDom.TSqlFragmentVisitor)
Microsoft.SqlServer.TransactSql.ScriptDom.BinaryQueryExpression.AcceptChildren(Microsoft.SqlServer.TransactSql.ScriptDom.TSqlFragmentVisitor)
Microsoft.SqlServer.TransactSql.ScriptDom.BinaryQueryExpression.Accept(Microsoft.SqlServer.TransactSql.ScriptDom.TSqlFragmentVisitor)
Microsoft.SqlServer.TransactSql.ScriptDom.BinaryQueryExpression.AcceptChildren(Microsoft.SqlServer.TransactSql.ScriptDom.TSqlFragmentVisitor)
SqlPackage 的参数 /ThreadMaxStackSize: 可用于所有命令,其指定运行 SqlPackage 进程的线程的最大堆栈大小。 默认值由运行 SqlPackage 的 .NET 版本确定。 设置较大的值会影响 SqlPackage 的整体性能。 然而,提高该值可能解决嵌套语句引发的栈溢出异常。 重构 T-SQL 代码,尽可能避免堆栈溢出异常。 如果无法重构,可以用该 /ThreadMaxStackSize: 参数作为变通方法。
使用 /ThreadMaxStackSize: 参数时,如果注意到性能受到影响,请将重复操作次数调至能够解决栈溢出异常的最低值。 参数的值以兆字节(MB)为单位。 例如,你可以测试像 10 和 100这样的值。
导入操作提示
对于包含大表或多索引表的导入,使用 /p:RebuildIndexesOfflineForDataPhase=True 或 /p:DisableIndexesForDataPhase=False 能提升性能。 这些属性分别将索引重新生成操作修改为脱机执行或不执行。 你可以利用这些属性和其他属性来调整 SqlPackage 导入 操作。
导入后索引会被禁用
为了高效加载数据,导入在数据阶段前禁用非聚类索引,之后重建它们(默认 /p:DisableIndexesForDataPhase=True 行为)。 如果导入在数据加载后但重建完成前被中断或失败,一个或多个非集群索引可以继续被禁用。 禁用的索引会保留在元数据中,但查询优化器会忽略它,这可能导致导入后查询变慢,而导入看似成功。
要查找被禁用的索引,请查看sys.indexes目录视图中的该is_disabled列:
SELECT OBJECT_SCHEMA_NAME(object_id) AS schema_name,
OBJECT_NAME(object_id) AS table_name,
name AS index_name
FROM sys.indexes
WHERE is_disabled = 1;
要重新启用禁用索引,请用 ALTER INDEX重建它。 使用 ALTER INDEX ALL ... REBUILD 以启用表中的所有已禁用索引:
ALTER INDEX ALL ON <schema>.<table> REBUILD;
更多信息请参见 “启用索引和约束”。
导出操作提示
为了让导出在事务上保持一致,可以确保导出过程中没有写入活动,或者你是从 交易一致 的数据库副本导出的。 如果在导入过程中遇到与外键约束相关的错误,则导出结果可能不具有事务一致性,原因是在导出过程中有记录被插入或更新。
导出期间的性能
导出过程中性能下降的一个常见原因是未解决的对象引用。 这个问题会导致 SqlPackage 多次尝试解析该对象。 例如,定义了一个视图,引用一个表,但该表已不存在于数据库中。 如果导出日志中出现未解析的引用,请考虑更正数据库的架构以提高导出性能。
在导出过程中,表数据将被压缩到 bacpac 文件中。 设置为 /p:CompressionOptionFast、 SuperFast或 NotCompressed 可能会提高导出速度,同时减少输出 bacpac 文件的压缩。
若要获取数据库架构和数据并跳过架构验证,请使用属性 执行/p:VerifyExtraction=False。 可能会生成无法导入的无效导出。
导出期间的磁盘空间
在操作系统磁盘空间有限且导出时耗尽的情况下,可以将 /p:TempDirectoryForTableData 数据缓冲以便导出到其他磁盘。 此操作所需的空间可能很大,相对于数据库的实际大小而言。 你可以通过设置这个和其他属性来调整 SqlPackage 导出 操作。
Azure SQL 数据库
以下提示专用于从 Azure 虚拟机 (VM) 运行针对 Azure SQL 数据库的导入或导出:
- 使用业务关键或高级层数据库实现最佳性能。
- 在虚拟机上使用 SSD 存储。
- 确保有足够的空间将 bacpac 解压缩。
- 从数据库所在的同一区域中的 VM 执行 SqlPackage。
- 在 VM 中启用加速网络。
有关使用 PowerShell 脚本收集导入操作细节的更多信息,请参见 Lesson Learned #211: 监控 SQLPackage 导入过程。
更多资源
Azure 数据库支持博客包含许多有关 Azure SQL 数据库故障排除和性能优化的文章,包括一些关于 SqlPackage 的文章。
一些最相关的文章包括:
- 优化 BACPAC 导入 - 正确使用 SqlPackage!
- 学习经验 #535:由于用户不兼容,Azure SQL 数据库中的 BACPAC 导入失败
- 学习课程 #523:使用 PowerShell 解析 SqlPackage 日志以测量导入时间
- 如何在导出/还原 Azure SQL DB 时跳过外部数据源引用
- 使用 SqlPackage/ADF 将 Azure SQL 数据库迁移到 SQL MI
- 经验与教训 #446:使用 PowerShell 简化 SQLPackage 日志调试
- 如何将 Sqlpackage 与托管标识配合使用
- 经验与教训 #298:使用 sqlpackage 导出数据库的持续时间很长
- 经验与教训 #281:由于系统内存不足异常,导出失败
- 经验与教训 #281:排查由于业务逻辑而在导入 bacpac 时出现的 CHECK 约束问题
- 经验与教训 #272:导入 Bacpac 文件时出现“执行超时已过期”错误消息
- 经验与教训 #213:如果已设置集成安全性,则无法设置 AccessToken 属性
- 经验与教训 #211:监视 SQLPackage 导入过程
- 经验教训 #51:托管实例 - 使用 Sqlpackage.exe 导入时不支持自动增长
- 经验与教训 #32:如何将多个数据库从 SQL Server 导出到 Bacpac
- 分步说明:如何将 SQLPackage 与访问令牌配合使用
- 使用 SQLPackage 将 Azure SQL DB 移动到本地 SQL Server 或 Azure VM 时出现排序规则冲突