web-dev-qa-db-ja.com

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

質問:

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

コンテキスト:

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

別の方法でこのデータをロードする必要がある場合は、遠慮なく私を懲戒して知らせてください。

28
spaghetticowboy

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

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

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

17
darin strait

BULK INSERTまたはbcpは、45,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:個々の挿入ステートメントの代わりに、一度に100または500ステートメントの場合はUNION ALLを使用します。

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に送信しようとはしないということです。

14
Aaron Bertrand

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

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

SSMS import data task.

9
datagod

複数のSqlBulkCopyを使用して、一時テーブルを作成します。新しいデータを一時テーブルに挿入し、一時テーブルのデータを既存のデータにマージします。 C#を使用した例 SqlBulkCopy.WriteToServerメソッド(DataTable) 。それが役に立てば幸い

0
Hung Vu

はい、できました。[〜#〜] bcp [〜#〜](一括コピープログラム)アプローチを試してOutOfMemoryの問題。

:SQL Server 2014で試してみました。

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

enter image description here

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

注:

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. その結果、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 
    

    一時停止

さあ、いくぞ!

0
Kms