使用 SqlPackage 排查问题和性能问题
在某些情况下,SqlPackage 操作会花费比预期更长的时间或无法完成。 本文介绍一些常见的建议策略,用于排查这些操作的性能问题或提高性能。 建议阅读每个操作的特定文档页以了解可用的参数和属性,可以将本文作为切入点来调查 SqlPackage 操作。
整体策略
一般来说,通过 SqlPackage 的 .NET 版本可以获得更好的性能,而不是通过 DacFramework.msi 安装的 .NET Framework 版本。
如果无法安装 SqlPackage dotnet 工具,则可从任何目录中的命令提示符执行 SqlPackage 命令:
- 下载适用于所用操作系统(Windows、macOS 或 Linux)的 .NET 8 版 SqlPackage 的 zip。
- 按照下载页上的指示将存档解压缩。
- 打开命令提示符,将目录 (
cd
) 更改为 SqlPackage 文件夹。
请务必使用最新版本的 SqlPackage,因为性能改进和漏洞修复会定期发布。
使用 SqlPackage 替换导入/导出服务
如果尝试使用导入/导出服务导入或导出数据库,则可以使用 SqlPackage 执行相同的操作,并对可选参数和属性进行更多控制。
若要导入,示例命令为:
./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 身份验证(以前的 Azure Active Directory)使用 多重身份验证 进行身份验证。 将 /ua:true
和 /tid:"yourdomain.onmicrosoft.com"
替换为用户名和密码参数。
常见问题
超时错误
如果出现与超时相关的问题,可以使用以下属性优化 SqlPackage 和 SQL 实例之间的连接:
/p:CommandTimeout=
:指定执行查询时命令超时(以秒为单位)。 默认:60/p:DatabaseLockTimeout=
:指定数据库锁定超时(以秒为单位)。 -1 可用于无限期等待,默认值:60/p:LongRunningCommandTimeout=
:指定长时间运行的命令超时(以秒为单位)。 默认值为 0,用于无限期等待。
客户端资源消耗
对于导出和提取命令,表数据将先传递到缓冲区的临时目录,然后再写入 bacpac/dacpac 文件。 相对于要导出数据的实际大小,该存储需求可能很大。 使用属性 /p:TempDirectoryForTableData=<path>
指定备用临时目录。
架构模型在内存中编译,因此对于大型数据库架构,运行 SqlPackage 的客户端计算机的内存需求可能很大。
服务器资源消耗低
默认情况下,SqlPackage 将最大服务器并行度设置为 8。 如果出现服务器资源消耗量较低的情况,增加 MaxParallelism
参数的值可以提高性能。
访问令牌
使用 /AccessToken:
或 /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)
连接
如果无法连接 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。
诊断
日志对于故障排除至关重要。 使用 /DiagnosticsFile:<filename>
参数将诊断日志捕获到文件中。
在运行 SqlPackage 之前设置环境变量 DACFX_PERF_TRACE=true
,可以记录更多与性能相关的跟踪数据。 若要在 PowerShell 中设置此环境变量,请使用以下命令:
Set-Item -Path Env:DACFX_PERF_TRACE -Value true
导入操作提示
如果导入包含大型表或具有多个索引的表,使用 /p:RebuildIndexesOfflineForDataPhase=True
或 /p:DisableIndexesForDataPhase=False
可以提高性能。 这些属性分别将索引重新生成操作修改为脱机执行或不执行。 这些属性和其他属性可用于优化 SqlPackage 导入操作。
导出操作提示
导出过程中性能下降的常见原因是未解析对象引用,这会导致 SqlPackage 多次尝试解析对象。 例如,定义了一个引用表的视图,而该表不再存在于数据库中。 如果导出日志中出现未解析的引用,请考虑更正数据库的架构以提高导出性能。
如果 OS 磁盘空间有限并在导出过程中耗尽,使用 /p:TempDirectoryForTableData
可以在备用磁盘上缓冲导出数据。 此操作所需的空间可能很大,相对于数据库的实际大小而言。 此属性和其他属性可用于优化 SqlPackage 导出操作。
在导出过程中,表数据将被压缩到 bacpac 文件中。 将 /p:CompressionOption
设置为 Fast
、SuperFast
或 NotCompressed
可以提高导出过程速度,同时减少对输出 bacpac 文件的压缩。
若要获取数据库架构和数据并跳过架构验证,请使用属性 /p:VerifyExtraction=False
执行导出。 可能会生成无法导入的无效导出。
Azure SQL 数据库
以下提示专用于从 Azure 虚拟机 (VM) 运行针对 Azure SQL 数据库的导入或导出:
- 使用业务关键或高级层数据库实现最佳性能。
- 在虚拟机上使用 SSD 存储。
- 确保有足够的空间解压缩 bacpac。
- 从数据库所在的同一区域中的 VM 执行 SqlPackage。
- 在 VM 中启用加速网络。
有关使用 PowerShell 脚本收集有关导入操作详细信息的详细信息,请参阅 经验与教训 #211:监视 SQLPackage 导入过程。
更多资源
Azure 数据库支持博客包含许多有关 Azure SQL 数据库故障排除和性能优化的文章,包括一些关于 SqlPackage 的文章。
一些最相关的文章包括:
- 使用 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 虚拟机时,排序规则发生冲突。