メモリを使い果たすことなく、多くの挿入を含む大きなスクリプトを実行するにはどうすればよいですか?


28

質問:

selectステートメントから約45,000の挿入があるスクリプトがあります。実行しようとすると、メモリが不足していることを示すエラーメッセージが表示されます。このスクリプトを実行するにはどうすればよいですか?

コンテキスト:

  1. クライアントが使用する別のアプリでアプリを快適に動作させるために、いくつかの新しいデータフィールドが追加されました。
  2. 現在のデータ項目をこれらの新しいフィールドの値にマッピングしたデータでいっぱいのクライアントからデータのスプレッドシートを取得しました。
  3. ステートメントを挿入するためにスプレッドシートを変換しました。
  4. ステートメントの一部のみを実行すると機能しますが、スクリプト全体は機能しません。
  5. いいえ。タイプミスはありません。

別の方法がある場合は、このデータをロードする必要がありますので、お気軽に私を責め、知らせてください。


SOに関する同様の質問:(stackoverflow.com/questions/222442/…)答えが役立つかどうかわからない
-jumpdart

回答:


17

SQL Server 2005の最大バッチサイズは65,536 *ネットワークパケットサイズ(NPS)です。NPSは通常4KBです。256 MBになります。つまり、挿入ステートメントはそれぞれ平均5.8 KBになります。それは正しくないように思えますが、おそらく余分なスペースや異常なものがそこにあるでしょう。

私の最初の提案は、すべてのINSERTステートメントの後に「GO」ステートメントを置くことです。これにより、45,000個のINSERTステートメントの単一バッチが45,000個の個別のバッチに分割されます。これは消化しやすいはずです。これらの挿入の1つが失敗した場合、犯人を見つけるのに苦労するかもしれないことに注意してください。トランザクションで自分自身を保護したい場合があります。エディターに適切な検索と置換(\ r \ nなどの戻り文字を検索して置換できる)またはマクロ機能がある場合は、これらのステートメントをすばやく追加できます。

2番目の提案は、ウィザードを使用してExcelから直接データをインポートすることです。ウィザードは、バックグラウンドで小さなSSISパッケージを作成し、実行します。この問題はありません。


2
すべてのステートメントのGO後?さて、別のスクリプトを使用してそれらを生成している場合、私は推測します。それ以外の場合は、1000 秒ごとに1つずつ配置します。トランザクションをアトミックにし、トランザクションのサイズを最小化することに関して、すべての行を一時テーブルまたはテーブル変数にロードしてから、そこからターゲットテーブルに一度にロードしませんか?INSERT
ニックチャマス

1000は1と同じくらい良いのですが、数えるのは難しいです。正直に言うと、彼はGOステートメントをたった1つ、中間点で、ステートメント21,500の近くで逃げるかもしれません。GO修正は、現在のスクリプトの複雑な編集やINSERTステートメントのカウント(行番号に直接マップされない可能性がある)を必要としないため、気に入っています。
ダリン海峡

2
確かに、1000ステートメントの不適切な近似でさえ十分です。:)
ニックチャマス

1
GOの追加は迅速かつ簡単な修正でした。25mbスクリプトは9分弱で問題なく実行されます。それが出たときのために、標準のパッチ展開プロセス内でそれを維持するためのスクリプトとしてそれを望んでいました。
spaghetticowboy

14

BULK INSERTまたはbcp45,000の挿入ステートメントよりも適切なオプションのようです。

挿入ステートメントに固執する必要がある場合、いくつかのオプションを検討します。

A:トランザクションを使用し、各ステートメントで100または500または1000ステートメントのバッチをラップして、ログおよびバッチへの影響を最小限に抑えます。例えば

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

B:個々の挿入ステートメントの代わりにUNION ALL、一度に100または500ステートメントに使用します。たとえば、

INSERT dbo.table(a, ...)
SELECT 1, ...
UNION ALL SELECT 2, ...
...
UNION ALL SELECT 500, ...
GO

INSERT dbo.table(a, ...)
SELECT 501, ...
UNION ALL SELECT 502, ...
...
UNION ALL SELECT 1000, ...
GO

簡潔にするためにエラー処理を省略しましたが、ポイントは、45,000の個々のステートメントの単一バッチをSQL Serverに送信しようとしないことです。


1
残念なことに、OPは2008+の機能であるテーブル値コンストラクターを使用できません。彼は、挿入を1000行のグループにバッチ処理する必要がありました。これは、TVCでグループ化できる最大数です。
ニックチャマス

バージョンタグが表示されるまで、これが最初の提案になります。
アーロンバートランド

2
@NickChammas- これらのパフォーマンスは、値句BTWの数で非線形に低下します。値を挿入するだけでなく、値を比較する多くの不必要な作業を行うため、2008 devインスタンスでコンパイル時間12.5分で2008年に10 列で1000行を挿入する再現で接続アイテムを送信しましパラメータ化されたときはより速く、見るべき値はありません)。2012年に大幅に改善されましたが、非線形パターンはまだ存在しており、後のバージョンで修正する必要があります。VARCHAR(800)
マーティンスミス

9

メモリ不足エラーが発生する理由はわかりませんが、より簡単な方法があります。

スプレッドシートからデータを区切り形式(csvなど)にエクスポートできる場合、SSMSのデータインポートウィザードを使用してデータを挿入できます。

SSMSインポートデータタスク。


thatsは便利ですが、クライアントデータベースにアクセスできません。私は、スクリプト内のパッチとdataloadsを準備する必要が
spaghetticowboy


0

はい、できます。OutOfMemoryの問題を回避するために、BCP(一括コピープログラム)アプローチを試しました。

:SQL Server 2014で試しました。

BCPでは、最初にソースデータベースデータをbcpファイル(ローカルディレクトリフォルダー内)にエクスポートしてから、そのbcpファイルを宛先データベースにインポートする必要があります。

ここに画像の説明を入力してください

以下は、ケーキウォークの手順です。

注意:

a)宛先データベースに空のテーブルが存在することを確認します

b)TempドライブがCドライブに存在することを確認します

  1. 以下に示すコマンドを使用して、Export_Data.batという名前のbatファイルを作成します。

    bcp.exe [Source_DataBase_Name].[dbo].[TableName] OUT "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 

    一時停止

  2. そのbatファイルを実行します。その結果、bcpファイルがTempフォルダーに生成されます。

  3. 次に、次のコマンドを使用して、Import_Data.batという名前の別のbatファイルを作成します。

    bcp.exe [Destination_DataBase_Name].[dbo].[TableName] IN "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 

    一時停止

さあ、いくぞ!


「入力、出力、またはフォーマットのオプションには有効なテーブル名が必要です」というエラーが表示されます。データをエクスポートしようとしたとき。
Sen Jacob

1
すべての属性値で試したコマンドを貼り付けてください。次の例に従ってください:bcp.exe ExportDB.dbo.AddressCountry OUT "C:\ Temp \ AddressCountry.bcp" -S "IN-L20054" -U "sa" -P "sa" -n -qその[ExportDB->ソースDB、AddressCountry->ソースDBに存在するテーブル、IN-L20054->マシン名、 "sa"はDBのユーザー名/
パスワード

今は持っていません。結局、SSMSのインポートデータ機能を使用しました。次に、MS OLE DB接続を使用してターゲットDB(v14.0)をソースDB(v.15.0)に接続しました。数百万行のデータをインポートするのは非常に高速でした。ありがとう!
センジェイコブ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.