アプリケーションのギアを上げよう
― Visual Studio 2010でアプリケーションのパフォーマンス・チューニング ―

第4回 DBアプリケーションのパフォーマンス・チューニング

亀川 和史
2011/11/15
Page1 Page2

更新処理

 以下では更新処理について解説する。

 LINQ to Entitiesでの更新は数行程度であれば問題ないが、CSV形式のファイルを基に多くのレコードを追加および更新するような場合は、SQL ServerにはbcpユーティリティやSSISを使用した方がはるかに効率的だ。

 また、データベースAのデータを基にしてデータベースBのデータを作成、更新するといったように、マスタから別のデータを作る場合も、ストアド・プロシージャを使用すれば、アプリケーション・サーバ側とデータベース・サーバ側で通信を発生させることもないため、性能面で有利になる。

 例えば、100万件のCSVファイルを以下のようなデータベースのマスタ・データとして登録する場合を考えてみよう。

100万件のCSVファイルを登録するための、データベースのマスタ・データ・テーブル

 CSVファイルから1行ずつ読み込んでEntity Frameworkでデータを登録するようなプログラムは、下記のようになる。紙面の都合上、最低限のエラー・チェックしか行っていない。

using System;
using System.Text;
using System.IO;

namespace DBRegister
{
  class Program
  {
    static 商品マスタ CSV2Data(string[] sourceItems)
    {
      return new 商品マスタ {
        商品CD = sourceItems[0],
        商品名 = sourceItems[1],
        有効フラグ= byte.Parse(sourceItems[2]),
        登録日 = sourceItems[3] == "" ? DateTime.MinValue : DateTime.Parse(sourceItems[3]),
        廃止日 = sourceItems[4] == "" ? DateTime.MinValue : DateTime.Parse(sourceItems[4]),
        仕入先CD = sourceItems[5],
        特注フラグ = sourceItems[6] == "1" ? true : false,
        容積 = int.Parse(sourceItems[7]),
        仕入価格 = decimal.Parse(sourceItems[8]),
        税率 = float.Parse(sourceItems[9]),
        税区分 = byte.Parse(sourceItems[10]),
        販売価格 = decimal.Parse(sourceItems[11]),
      };
    }

    static void Main(string[] args)
    {
      using (var dbContext = new AtmarkITEntities()) {
        using (var FileReader = new StreamReader(@".\data\Product_master.csv",
          Encoding.GetEncoding(932))) {
          while (FileReader.EndOfStream == false) {
            var Recored = FileReader.ReadLine();
            var Items = Recored.Split(',');
            var RegisterItems = CSV2Data(Items);
            dbContext.AddTo商品マスタ(RegisterItems);
          }
        }
        dbContext.SaveChanges();
      }
    }
  }
}
CSVファイルから1行ずつ読み込んでEntity Frameworkでデータを登録するコード例

 この処理でリモートのSQL Serverを登録先にすると、かなりの時間がかかる。正確にはSaveChangesメソッドを呼び出したタイミングでSQL Server側でコミット処理が走り、ここでかなり待つことになる。また、SQL Serverのトランザクション・ログの容量によっては更新処理が失敗するかもしれない。

 SaveChangesメソッド(=データの登録)を適当なタイミング(1000行読み込んだタイミングで実行するなど)で呼び出せば、SaveChangesメソッドの処理時間を短くすることもできるが、処理中にエラーになった場合は一部登録されたレコードを削除する、もしくは、途中からデータ登録を再開するといった機能を組み込む必要がある。

 こういったリモートSQL Serverへの大量のデータ登録時には、SQL Serverに付属している[データのインポートおよびエクスポート ユーティリティ](以下、SSIS)を使用する方が断然高速に行える。実際にやってみよう(以下の画面を参照)。64bit版と32bit版の2種類が用意されているが、どちらでもできることは同じである。


[次へ]ボタンを押す

[データソースの選択]ページ(1):全般
CSVファイルなので、フラット・ファイル・ソースを選択する。列や詳細条件で変換時の設定を変更することができる。
  拡張子が.csvもしくは.txtのファイルを選択する。
  ロケールを指定する。選択した地域によって区切り記号が変わる。
  ファイルのエンコーディング(「 Shift-JIS」「ISO-2022-JP」「EUC-JP」など)を指定する。
  区切り記号の形式(=Windowsのコントロール・パネルの[地域と言語]で指定された記号)を選択する。ロケールで「日本」を指定した場合、OSの設定を変更していなければ「,(コンマ)」になる。
  テキスト修飾子。ロケールが「日本」の場合は指定しない。
  ヘッダ行の区切り記号を指定する。特別な理由がない限り、「{CR}{LF}」のままでよい。
  読み飛ばす行数。最初の1行目がヘッダになっている場合もあるので、そういうレコードを読み込みたくない場合、何行読み飛ばすかを指定する。
  チェックした場合、SQL Server側に複数行データを取り込んだときに先頭行をそのまま列名として使用する。

左のリストから[列]を選択

[データソースの選択]ページ(2):列
左側のリストから[列]を選択したときに実際の区切りをプレビューで見ることができる。
  読み込みに問題があるようならば行区切りの記号を変更する。
  列の区切りがWindowsの既定(日本語の場合「コンマ」)でない場合、ここで変更する。
  更新を確定する。
  現在の設定をリセットする。

左のリストから[詳細設定]を選択

[データソースの選択]ページ(3):詳細設定
左側のリストの[詳細設定]で列の詳細設定を変更できる。[DataType]プロパティの既定値が「文字列 [DT_STR]」となっているので、取り込み時にエラーが出る場合、ここで変更する必要がある。左側のリストの[プレビュー]で問題なければ[次へ]ボタンを押す。
  読み込まれている列の数。
  列に対して、SQL Server側に読み込むときのルールを設定する。読み込み時に警告が出るようであれば、[DataType]プロパティを設定して、明示的に指定する。

[次へ]ボタンを押す

[変換先の選択]ページ
登録先サーバおよび、データベースを選択して、[次へ]ボタンを押す。
  取り込むサーバ名。
  認証の種類を選択する。
  取り込むデータベース名を指定する。

[次へ]ボタンを押す

[コピー元のテーブルおよびビューの選択]ページ
ここで変換先のテーブルを選択する。テーブルは新規に作成することもできる。[マッピングの編集]ボタンを押して、マッピングを確認する。
  変換先データベースを指定するか、新規作成か選択する。
  [列マッピング]ダイアログを呼び出す。
  プレビューを表示する

[マッピングの編集]ボタンを押す

[列マッピング]ダイアログ
マッピングの変換先の型および、変換先のデータを残す/残さないといった情報を確認・変更して[OK]ボタンを押す。戻った画面で[次へ]ボタンを押すと、最後の確認画面が表示される。
  変換先テーブル内のレコードを削除する。
  変換先テーブル内に追加する。もしもプライマリ・キー(primary key)が重複するようなレコードを追加するとエラーになる。
  変換元データのIDを変換先テーブルのIDとしてID列に挿入する。

[OK]ボタンを押す

[すぐに実行する]チェックボックスにチェックを入れて[完了]ボタンを押す
SSISの利用手順

 本稿の例ではクライアントにSQL Server 2008 R2 Express Editionを使っているため、[すぐに実行する]しか選択することができない。しかし、画面下部の注意書きにあるように、Standard以上のエディションではSQL Serverにパッケージとして登録して、SQL ServerのAgentタスクとして実行できる。例えば、定期的に外部からCSVファイルをデータベースに登録するような処理であればプログラムを作る必要はない。そういった処理を目的としたプログラムを作る前に、SSISを実際に試してみるとよいだろう。

 SSISで先ほどと同じ1万行のデータを登録する場合、10秒程度で終了した。Entity Frameworkの先ほどのプログラムと比較すると、かなり高速に終了することが分かる。

 業務アプリケーションでデータベースAからデータを読みながら、そのデータでデータベースBを更新するという処理も、同様にネットワークでデータのやり取りが発生するため、遅くなる。速度だけをポイントにするならばストアド・プロシージャに移行すれば高速化が期待できる。

 次回はWebサービスのパフォーマンス・チューニングを説明する。end of article


 INDEX
  アプリケーションのギアを上げよう ― Visual Studio 2010でアプリケーションのパフォーマンス・チューニング
  第4回 DBアプリケーションのパフォーマンス・チューニング
    1.データ・アクセスについて:LINQとストアド・プロシージャ
  2.データ・アクセスについて:更新処理

インデックス・ページヘ 「アプリケーションのギアを上げよう」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH