この数週間、データベースをコピーできる汎用スクリプトを作成してきました。目標は、サーバー上の任意のデータベースを指定して、それを別の場所にコピーできるようにすることです。指定されたコンテンツのみをコピーする必要があります。コピーされる正確なコンテンツは、構成ファイルで指定されます。このスクリプトは、約 10 の異なるデータベースで使用され、毎週実行されます。そして最終的に、500GB もの大きなデータベースの約 3% から 20% しかコピーしていません。これを実現するために SMO アセンブリを使用しています。SMO を使用するのはこれが初めてで、スキーマ オブジェクト、ファイル グループなどをコピーする一般的な方法を作成するのに時間がかかりました。(実際には、いくつかの悪いストアド プロシージャを見つけるのに役立ちました)。
全体的に、パフォーマンスが不足している(そして時々タイムアウトする)作業スクリプトがあり、皆さんが助けてくれることを望んでいました。WriteToServer コマンドを実行して大量のデータ (> 6GB) をコピーすると、1 時間のタイムアウト期間に達します。テーブル データをコピーするためのコア コードを次に示します。スクリプトは PowerShell で記述されています。
$query = ("SELECT * FROM $selectedTable " + $global:selectiveTables.Get_Item($selectedTable)).Trim()
Write-LogOutput "Copying $selectedTable : '$query'"
$cmd = New-Object Data.SqlClient.SqlCommand -argumentList $query, $source
$cmd.CommandTimeout = 120;
$bulkData = ([Data.SqlClient.SqlBulkCopy]$destination)
$bulkData.DestinationTableName = $selectedTable;
$bulkData.BulkCopyTimeout = $global:tableCopyDataTimeout # = 3600
$reader = $cmd.ExecuteReader();
$bulkData.WriteToServer($reader); # Takes forever here on large tables
ソース データベースとターゲット データベースは別のサーバーにあるため、ネットワーク速度も追跡しました。ネットワーク使用率が 1% を超えることはありませんでした。これは私にとって非常に驚きでした。しかし、サーバー間でいくつかの大きなファイルを転送すると、ネットワーク使用率が最大 10% に跳ね上がります。$bulkData.BatchSize を 5000 に設定しようとしましたが、実際には何も変わりませんでした。BulkCopyTimeout をさらに大きくすると、タイムアウトだけが解決されます。ネットワークが十分に活用されていない理由を知りたいです。
他の誰かがこの問題を抱えていましたか?ネットワーキングまたは一括コピーに関する提案は大歓迎です。さらに情報が必要な場合はお知らせください。
ありがとう。
アップデート
SqlBulkCopy のパフォーマンスを向上させるいくつかのオプションを微調整しました。たとえば、トランザクション ログをシンプルに設定したり、デフォルトの行ロックの代わりに SqlBulkCopy にテーブル ロックを提供したりします。また、一部のテーブルは、特定のバッチ サイズに対して最適化されています。全体として、コピーの所要時間は約 15% 短縮されました。そして、各データベースのコピーを異なるサーバーで同時に実行します。しかし、データベースの 1 つをコピーするときに、まだタイムアウトの問題があります。
大規模なデータベースの 1 つをコピーすると、次の例外が一貫して発生するテーブルがあります。
System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
BulkCopyTimeout の近くにないテーブルのコピーを開始してから約 16 分後にスローされます。最後にテーブルが完全にコピーされるという例外が発生しますが。また、そのテーブルを切り捨てて、そのテーブルに対してのみプロセスを再起動すると、テーブルは問題なくコピーされます。しかし、そのデータベース全体をコピーするプロセスを実行すると、その 1 つのテーブルに対して常に失敗します。
その障害のあるテーブルをコピーする前に、プロセス全体を実行して接続をリセットしようとしましたが、それでもエラーが発生しました。私の SqlBulkCopy と Reader は、各テーブルの後に閉じられます。毎回その時点でスクリプトが失敗する原因として他に何が考えられるかについて何か提案はありますか?
CREATE TABLE [dbo].[badTable](
[someGUID] [uniqueidentifier] NOT NULL,
[xxx] [uniqueidentifier] NULL,
[xxx] [int] NULL,
[xxx] [tinyint] NOT NULL,
[xxx] [datetime] NOT NULL,
[xxx] [datetime] NOT NULL,
[xxx] [datetime] NOT NULL,
[xxx] [datetime] NULL,
[xxx] [uniqueidentifier] NOT NULL,
[xxx] [uniqueidentifier] NULL,
CONSTRAINT [PK_badTable] PRIMARY KEY NONCLUSTERED
(
[someGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ターゲット DB にこのテーブルのインデックスが存在しません。