データ量に負けない!C#でSQL Serverへの大量データ挿入を高速化するテクニック

2024-04-06

C# で大量のデータを SQL Server に高速にバルク挿入する方法

SqlBulkCopy を使用したバルク挿入の利点

  • 高速: 従来の INSERT ステートメントよりも大幅に高速なデータ転送速度を実現します。
  • 効率的: データベースとの通信を最小限に抑え、サーバーリソースの負荷を軽減します。
  • メモリ使用量が少ない: データをバッファリングせずに直接データベースに書き込むため、メモリ使用量を抑えられます。

SqlBulkCopy を使用したバルク挿入の手順

  1. 接続文字列を作成
string connectionString = "Data Source=localhost;Initial Catalog=TestDB;Integrated Security=True;";
  1. SqlBulkCopy インスタンスを作成
using (var sqlBulkCopy = new SqlBulkCopy(connectionString))
{
  // 設定
}
  1. データソースを設定

データソースは、DataTable、DataReader、または IEnumerable<T> オブジェクトなど、さまざまな形式のデータソースを設定できます。

  1. 列マッピングを設定

データソースの列とターゲットテーブルの列をマッピングする必要があります。

  1. バルク挿入を実行
sqlBulkCopy.WriteToServer(dataTable);

パフォーマンスをさらに向上させるためのヒント

  • データ型を一致させる: データソースとターゲットテーブルの列のデータ型を一致させると、変換処理が不要になり、パフォーマンスが向上します。
  • バッチサイズを調整する: バッチサイズは、1 回の書き込み処理で送信されるデータの量を指定します。適切なバッチサイズは、データ量やネットワーク帯域幅によって異なります。
  • バルク挿入エラー処理

バルク挿入処理中にエラーが発生する可能性があります。エラー処理を実装して、問題を特定し、解決する必要があります。




using (var connection = new SqlConnection("Data Source=localhost;Initial Catalog=TestDB;Integrated Security=True;"))
{
  // データテーブルを作成
  var dataTable = new DataTable();
  dataTable.Columns.Add("Id", typeof(int));
  dataTable.Columns.Add("Name", typeof(string));

  // データを追加
  for (int i = 0; i < 10000; i++)
  {
    dataTable.Rows.Add(i, $"Name{i}");
  }

  // SqlBulkCopy インスタンスを作成
  using (var sqlBulkCopy = new SqlBulkCopy(connection))
  {
    sqlBulkCopy.DestinationTableName = "MyTable";

    // 列マッピング
    sqlBulkCopy.ColumnMappings.Add("Id", "Id");
    sqlBulkCopy.ColumnMappings.Add("Name", "Name");

    // バルク挿入を実行
    sqlBulkCopy.WriteToServer(dataTable);
  }
}

このコードは、10,000 行のデータを含む DataTable を "MyTable" テーブルにバルク挿入します。

その他のデータソース

DataReader を使用する場合

using (var connection = new SqlConnection("Data Source=localhost;Initial Catalog=TestDB;Integrated Security=True;"))
{
  // DataReader を作成
  var cmd = new SqlCommand("SELECT * FROM MySourceTable", connection);
  var reader = cmd.ExecuteReader();

  // SqlBulkCopy インスタンスを作成
  using (var sqlBulkCopy = new SqlBulkCopy(connection))
  {
    sqlBulkCopy.DestinationTableName = "MyTable";

    // 列マッピング
    for (int i = 0; i < reader.FieldCount; i++)
    {
      sqlBulkCopy.ColumnMappings.Add(reader.GetName(i), reader.GetName(i));
    }

    // バルク挿入を実行
    sqlBulkCopy.WriteToServer(reader);
  }
}

IEnumerable<T> オブジェクトを使用する場合

using (var connection = new SqlConnection("Data Source=localhost;Initial Catalog=TestDB;Integrated Security=True;"))
{
  // IEnumerable<T> オブジェクトを作成
  var data = new List<MyObject>();
  for (int i = 0; i < 10000; i++)
  {
    data.Add(new MyObject { Id = i, Name = $"Name{i}" });
  }

  // SqlBulkCopy インスタンスを作成
  using (var sqlBulkCopy = new SqlBulkCopy(connection))
  {
    sqlBulkCopy.DestinationTableName = "MyTable";

    // 列マッピング
    sqlBulkCopy.ColumnMappings.Add("Id", "Id");
    sqlBulkCopy.ColumnMappings.Add("Name", "Name");

    // バルク挿入を実行
    sqlBulkCopy.WriteToServer(data);
  }
}

public class MyObject
{
  public int Id { get; set; }
  public string Name { get; set; }
}

これらのサンプルコードは、C# で大量のデータを SQL Server に高速にバルク挿入する方法を理解するのに役立つでしょう。




C# で大量のデータを SQL Server に挿入する他の方法

SqlBulkCopy.WriteToServer メソッドの代わりに WriteToServerAsync メソッドを使用すると、データをストリーミング挿入できます。これは、メモリ使用量をさらに削減したい場合に役立ちます。

Table-Valued Parameter (TVP)

TVP を使用すると、データをパラメータとしてストアドプロシージャに渡すことができます。これは、複雑なデータ挿入処理を行う場合に役立ちます。

データインポートウィザード

SQL Server Management Studio (SSMS) には、データインポートウィザードが用意されています。これは、GUI を使用してデータを簡単にインポートしたい場合に役立ちます。

ADO.NET Entity Framework

Entity Framework を使用すると、コードベースをよりシンプルに保ちながら、データベースとの CRUD 操作を行うことができます。

第三者製ライブラリ

FastMember や Dapper などの第三者製ライブラリを使用して、データ挿入処理をさらに高速化することができます。

最適な方法は、データ量、データソース、パフォーマンス要件などによって異なります。

一般的な目安

  • 少量のデータの場合は、INSERT ステートメント で十分です。
  • 大量のデータの場合は、SqlBulkCopy を使用するのが最善の方法です。
  • 複雑なデータ挿入処理を行う場合は、TVP を検討してください。
  • GUI を使用してデータをインポートしたい場合は、データインポートウィザード を使用してください。
  • コードベースをよりシンプルに保ちたい場合は、Entity Framework を使用してください。
  • データ挿入処理をさらに高速化したい場合は、第三者製ライブラリ を検討してください。

C# で大量のデータを SQL Server に挿入する方法はいくつかあります。それぞれの方法にはメリットとデメリットがあるので、要件に合わせて最適な方法を選択する必要があります。


c# sql sql-server


【SQL Server初心者向け】「オブジェクトが見つかりません」エラーの解決方法をわかりやすく解説

オブジェクト名の誤りクエリ内で指定したオブジェクト名に誤りがある可能性があります。スペルミスや大小文字の誤り、または完全修飾名の省略などが考えられます。オブジェクト名は正確に記述されていることを確認してください。オブジェクトが存在しない指定したオブジェクトが実際に存在しない可能性があります。オブジェクトが削除されたか、名前が変更された可能性があります。オブジェクトが存在するかどうかを確認してください。...


NOLOCK ヒントの代替手段:ロック競合を回避し、パフォーマンスを向上させる方法

NOLOCK の利点と欠点利点:ロック競合を回避し、クエリのパフォーマンスを向上させる可能性があります。読み取り専用のワークロードに適しています。データの整合性を損なう可能性があります。更新操作との併用は避けるべきです。副作用を伴う操作には使用しないでください。...


PostgreSQLで過去10日間のレコードを抽出!WHERE句とdate_trunc関数を使いこなそう

このチュートリアルでは、PostgreSQLを使用して過去10日間のレコードを一覧表示する2つの方法を説明します。方法1:WHERE句とCURRENT_DATE関数を使用するこの方法は、CURRENT_DATE関数を使用して現在の日付を取得し、WHERE句で比較することで過去10日間のレコードを抽出します。...


参考資料:FLOOR関数、DATEPART関数、CAST関数、CONVERT関数、DATEADD関数、DATEDIFF関数、CASE式

SQL Serverで日付時刻列をグループ化する際、時間情報も考慮すると、グループ数が多くなり、分析が複雑になる場合があります。そこで、時間情報を無視してグループ化する方法を紹介します。方法以下の2つの方法があります。FLOOR関数は、指定された精度で数値を切り捨てます。日付時刻列に対してFLOOR関数を使うことで、時間情報を切り捨てて日付のみでグループ化できます。...


ブラウザの履歴やスクリーンショットからSQLクエリを復元する方法

SQL Server Management Studio (SSMS) やその他のツールを使用しているときに、誤って SQL クエリ スクリプトを保存せずに閉じてしまった場合、復元できる可能性があります。 いくつかの方法があり、状況によって最適な方法が異なります。...