記事
Mihoko Iijima · 2020年11月10日 4m read

大量データのロードを高速化する方法

これはInterSystems FAQ サイトの記事です

インデックスが複数定義されているクラス/テーブルへ csv 形式等のシーケンシャルファイルから大量データをデータベースに登録する際、推奨される登録方法として、データ登録時インデックスを生成させず、登録完了後に一括でインデックスを生成する 方法があります。

この方法は、新規に大量のレコードを一括登録する際に最も有効な手段となります。

<メモ>
大量のデータを追加登録する際には、既存のデータ量と新規データ量のバランスにより、この手法が有効でないケースもあります。その場合は、インデックスの再構築を範囲指定で行うこともできます。

 

説明に使用するクラス定義例は以下の通りです。

Class ISJ.QL2 Extends %Persistent
{

Property Name As %String;

Property Title As %String;

Property Sex As %String;

Property Company As %String;

Property Phone As %String;

Property City As %String;

Property State As %String;

Property Zip As %String;

Index NameIndex On Name;

Index CompanyIndex On Company;

Index PhoneIndex On Phone;

}

 

データロードを行うクラスメソッド例は以下の通りです。

ClassMethod ImportFromFile(pFile As %String)
{
 #dim Err As %Exception.AbstractException
 //埋め込みSQLを使用してインポート
 Try {
  if $get(pFile)="" {
   write "インポートファイルを指定してください",!
   quit
  }
  if ##class(%File).Exists(pFile)=0 {
   write "指定したファイルは存在しません。ファイル名、パスを確認してください",!
   quit
  }
  set filestream=##class(%Stream.FileCharacter).%New()
  do filestream.LinkToFile(pFile)
  set tDelim=";"
  while filestream.AtEnd=0 {
   //改行があるところまでRead
   set tLine=filestream.ReadLine()
   set pCity = $Piece(tLine,tDelim,1) //City
   set pCompany = $Piece(tLine,tDelim,2) //Company
   set pName = $Piece(tLine,tDelim,3) //Name
   set pPhone = $Piece(tLine,tDelim,4) //Phone
   set pSex = $Piece(tLine,tDelim,5) //Sex
   set pState = $Piece(tLine,tDelim,6) //State
   set pTitle = $Piece(tLine,tDelim,7) //Title
   set pZip = $Piece(tLine,tDelim,8) //Zip
     &sql(INSERT %NOINDEX INTO ql2 (Name, Title, Sex, Company, Phone, City, State, Zip) values (:pName, :pTitle, :pSex, :pCompany, :pCity, :pCity, :pState, :pZip))
   // SQL文でエラーがある場合の処理
   if SQLCODE<0 {
      throw ##class(%Exception.SQL).CreateFromSQLCODE(SQLCODE,%msg)
   }
  }
  // 最後にテーブルのインデックス再構築を実行
  set st=..%BuildIndices()
  $$$THROWONERROR(Err,st) // エラーが発生した場合Catchへ移動
 }
 Catch Err {
  write "エラーが発生しました",!
  write Err.DisplayString(),!
 }
}

 

クラスメソッドでは、以下のデータ形式で作成されたファイルを入力しながらデータ登録後にインデックスを構築しています(ランダム生成させたデータを使用しています)。

;京都市上京区;新光損保 株式会社;橋本,京子;0363-7728-2499;女;京都府;国際製品スペシャリスト;6020808
;札幌市西区;NTS工業 株式会社;本田,亮;0325-6753-6990;男;北海道;アシスタント管理者;0630003
;呉市;セコミ薬品 株式会社;川原,明雄;0670-9635-5468;男;広島県;副衛生士;7370145
;春日部市;SESコミュニケーションズ 株式会社;大島,江美;0407-3421-5865;女;埼玉県;研究ディレクタ;3440065
;上高井郡小布施町;電金証券 有限会社;松本,亮;053-3208-4665;女;長野県;副会計士;3810202
;茅野市;ビーエスシ薬品 株式会社;渡部,弘明;0996-5061-8567;女;長野県;国際マーケティングマネージャ;3910212
;中川郡豊頃町;電金技研 有限会社;根本,由貴;0647-5142-4961;男;北海道;国際ウェブマスタ;0895461
;尼崎市;SES石油 有限会社;川口,博美;0744-3148-1523;男;兵庫県;副会計士;6610978
;北松浦郡吉井町;三友製造 株式会社;阿部,陽子;0554-2270-3308;男;長崎県;副システムエンジニア;8596304

 

サンプルコードの以下の文で、全レコードに対してインデックスを構築しています。

Do ..%BuildIndices()

 

サンプルコードで使用している埋め込み SQL では、実行後に %ROWID 変数を使用して INSERT によって設定された ID 値を取得できます。

例えば、INSERT したレコードのインデックスのみを構築したい場合は、%BuildIndices() メソッドの第 2 引数(pAutPurge)に 0 を指定し、第 5 引数(pStartID)および第 6 引数(pEndID)に ID を指定することで実行できます。

インデックス構築方法について詳細は、ドキュメントもご参照ください。

00
1 0 0 48
Log in or sign up to continue