針對 SqlPackage 的問題與效能進行疑難排解

在部分案例中,SqlPackage 作業花費的時間超乎預期或無法完成。 此文章描述一些常見的建議策略,以針對這些作業進行疑難排解或改善效能。 儘管建議您閱讀每個動作適用的特定文件頁面來了解可用的參數與屬性,但可將此文章當作調查 SqlPackage 作業的起點。

整體策略

一般指導方針是透過 .NET 版本的 SqlPackage 取得更好的效能,而不是透過 DacFramework.msi 安裝的 .NET Framework 版本。

如果你無法安裝 SqlPackage dotnet 工具,該工具能讓你在任何目錄的命令提示字元執行 SqlPackage 指令:

  1. 在適用於您作業系統 (Windows、macOS 或 Linux) 的 .NET 8 上,下載 SqlPackage 的 zip 檔案。
  2. 按照下載頁面指示解壓壓縮檔案。
  3. 開啟命令提示字元,並將目錄變更為 (cd) SqlPackage 資料夾。

請使用最新版本的 SqlPackage,因為效能改進與錯誤修正會定期發布。

以 SqlPackage 取代匯入/匯出服務

如果曾嘗試使用匯入/匯出服務來匯入或匯出資料庫,您可以使用 SqlPackage 來執行相同作業,並且能夠更充分控制選擇性參數與屬性。 部落格文章《最佳化 BACPAC 匯入 - 正確使用 SqlPackage!》逐步講解了如何使用 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 控制診斷輸出的細節程度。 使用 InformationVerbose 的值以取得更多詳細資訊。

在執行 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 的憑證驗證,但將 token 傳給指令時可能會很棘手。 如果你在 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];

以下是解決此錯誤的原因和解決方案:

  1. 確認您要匯入的目的地是否為空資料庫。
  2. 如果你的資料庫有使用屬性DEFAULT(SQL Server 會隨機指派約束名稱)和明確命名的限制,則同名的限制可能會被建立兩次。 使用所有明確命名的限制(不使用 DEFAULT),或使用所有系統定義的名稱(使用 DEFAULT)。
  3. 手動編輯 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)為單位。 例如,你可以測試像 10100這樣的值。

匯入動作提示

對於包含大型資料表或多索引資料表的匯入,使用 /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:CompressionOptionFastSuperFastNotCompressed 可能會提升匯出速度,同時減少輸出 bacpac 檔案的壓縮。

若要在略過結構描述驗證的情況下取得資料庫結構描述與資料,請使用具有屬性的功能進行匯出。 可能會產生無效的匯出,無法被匯入。

匯出時的磁碟空間

當作業系統磁碟空間有限且匯出時用盡時,請將 /p:TempDirectoryForTableData 資料緩衝至替代磁碟。 此動作所需的空間可能很大 (相對於資料庫的完整大小)。 你可以透過設定這個和其他屬性來調整 SqlPackage 匯出 操作。

Azure SQL Database

下列提示是針對從 Azure 虛擬機器 (VM) 執行匯入或匯出 Azure SQL Database 的特定提示:

  • 使用業務關鍵或進階層資料庫來獲得最佳效能。
  • 在 VM 上使用 SSD 儲存體。
  • 請確定有足夠的空間來解壓縮 bacpac。
  • 從與資料庫相同區域中的 VM 執行 SqlPackage。
  • 在 VM 中啟用加速網路。

欲了解更多使用 PowerShell 腳本收集匯入操作細節的資訊,請參閱 Lesson Learned #211:監控 SQLPackage 匯入流程

更多資源

Azure 資料庫支援部落格包含許多文章,涉及 Azure SQL 資料庫的疑難排解和效能微調,包括有關 SqlPackage 的數篇文章。

其中一些最相關的文章包括: