SqlPackage に関する問題とパフォーマンスのトラブルシューティング

シナリオによっては、SqlPackage の操作に予想以上の時間がかかることや、操作が完了しないことがあります。 この記事では、これらの操作のトラブルシューティングやパフォーマンス向上のためによく提案される戦術について説明します。 使用できるパラメーターやプロパティを理解するには各アクションの特定のドキュメントのページを読むことをお勧めしますが、SqlPackage の操作を調べるときはこの記事が出発点となります。

全体的な戦略

一般的なガイドラインとして、DacFramework.msi を使用してインストールされた .NET Framework バージョンではなく、SqlPackage の .NET バージョンを使用することでパフォーマンスを向上させることができます。

もしSqlPackageの dotnetツールをインストールしられない場合、このツールは任意のディレクトリのコマンドプロンプトからSqlPackageコマンドを実行できます。

  1. お使いのオペレーティングシステム (Windows、macOS、または Linux) 用の .NET 8 上の SqlPackage の zip をダウンロードします。
  2. ダウンロードページの指示通りにアーカイブを解凍してください。
  3. コマンド プロンプトを開き、ディレクトリ (cd) を SqlPackage フォルダーに変更します。

パフォーマンス向上やバグ修正が定期的にリリースされているため、最新のSqlPackageバージョンを使用してください。

Import/Export サービスの代わりに SqlPackage を使用する

Import/Export サービスを使ってデータベースをインポートまたはエクスポートしようとしている場合は、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:または/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];

このエラーの原因と回避のための解決策を次に示します。

  1. インポート先が空のデータベースであることを確認します。
  2. もしデータベースにDEFAULT属性(SQL Serverが制約にランダムな名前を割り当てる)と明示的に名前が付けられた制約を持つ制約がある場合、同じ名前の制約が2回作成されることがあります。 明示的に名前が付けられた制約をすべて使う( 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 のパラメーターは、SqlPackage プロセスを実行するスレッドの最大スタック サイズを指定するすべてのコマンド (/ThreadMaxStackSize:) で使用できます。 既定値は、SqlPackage を実行する .NET バージョンによって決まります。 大きな値を設定すると、SqlPackageの全体的なパフォーマンスに影響を及ぼします。 しかし、この値を増やすことで、ネスト文によるスタックオーバーフロー例外が解決される可能性があります。 可能な限りスタックオーバーフロー例外を避けるためにT-SQLコードをリファクタリングしてください。 リファクタリングできない場合は、 /ThreadMaxStackSize: パラメータを回避策として使う。

/ThreadMaxStackSize:パラメータを使うときは、パフォーマンスに影響を感じた場合、スタックオーバーフロー例外を解決できる最小値まで繰り返し操作を調整します。 パラメータの値はメガバイト(MB)単位です。 例えば、 10100のような値をテストできます。

インポート アクションのヒント

大きなテーブルや多数のインデックスを持つテーブルを含むインポートでは、 /p:RebuildIndexesOfflineForDataPhase=True/p:DisableIndexesForDataPhase=False を使うことでパフォーマンスが向上します。 これらのプロパティは、それぞれインデックス再構築操作がオフラインで発生するか、発生しないように変更します。 これらのプロパティやその他のプロパティを使って SqlPackage Import 操作を調整できます。

インポート後はインデックスが無効になります

データを効率的に読み込むために、インポートはデータフェーズの前に非クラスタ化されたインデックスを無効にし、その後に再構築します(デフォルトの /p:DisableIndexesForDataPhase=True 動作です)。 データの読み込み後から再構築が完了する前にインポートが中断または失敗した場合、1つ以上の非クラスタインデックスは無効化されたままにできます。 無効化されたインデックスはメタデータに残りますが、クエリ最適化器はそれを無視するため、インポート後に成功しているように見えるクエリが遅くなることがあります。

無効化されたインデックスを探すには、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:CompressionOptionFastSuperFast、またはNotCompressedに設定すると、出力の圧縮を減らしながらエクスポート速度が向上するかもしれません。

スキーマ検証をスキップしながらデータベース スキーマとデータを取得するには、 プロパティで/p:VerifyExtraction=Falseを実行します。 インポートできない無効なエクスポートが生成される可能性があります。

エクスポート中のディスク領域

OSのディスク容量が制限され、エクスポート中に使い切られる場合は、 /p:TempDirectoryForTableData を使ってデータをバッファリングし、代替ディスクにエクスポートします。 この操作に必要な領域が大きくなる場合があり、データベースのフル サイズに関連します。 SqlPackage エクスポート操作は、このプロパティやその他のプロパティを設定することで調整できます。

Azure SQL Database

次のヒントは、Azure 仮想マシン (VM) から Azure SQL Database に対してインポートまたはエクスポートを実行する場合に固有のものです。

  • パフォーマンスを最適化するには、Business Critical または Premium レベルのデータベースを使います。
  • VM で SSD ストレージを使用します。
  • bacpac を解凍するのに十分なスペースがあることを確認します。
  • データベースと同じリージョン内の VM から SqlPackage を実行します。
  • VM で高速ネットワークを有効化します。

インポート操作の詳細をPowerShellスクリプトで収集する方法については、 Lesson Learned #211: Monitoring SQLPackage Import Processをご覧ください。

その他のリソース

Azure Database サポート ブログには、SqlPackage に関するいくつかの記事を含む、Azure SQL Database のトラブルシューティングとパフォーマンス チューニングに関する多くの記事が含まれています。

最も関連性の高い記事の一部を次に示します。