#43 | さまざまなエクスポート方法の比較 | ||||||||||||||||||||||||||
Accessでは、テーブルやクエリのレコードを簡単に外部のさまざまなファイル形式に出力することができます。メニューバーの操作で個々に出力することもできますし、マクロを使って自動化することもできます。さらにVBAを使えば、テーブルやクエリのレコードを1件ずつ読み込んで、フィールドごとに任意の値に加工しながら出力することも可能です。
DoCmdオブジェクトについては、ExcelワークシートはTransferSpreadsheetメソッド、他はTransferTextメソッドを使うことになります。また、Print #ステートメントを使ってのエクスポートについては、一般的にはCSVファイル出力が多いはずですので、CSVファイルへの出力のみをテストするものとします。つまり、全体として4通りのパターンでテスト・比較することになります。 テストに用いるプログラムコードですが、以下のようなものを用意しました。 Sub ExportTest() Dim dbs As Database Dim rst As Recordset Dim lngFileNum As Long Dim iintLoop As Integer ts_Watch "処理開始", True For iintLoop = 1 To 10 'テストパターン1 DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, _ "tbl受注", "受注.XLS" ts_Watch "XLSエクスポート" 'テストパターン2 DoCmd.TransferText acExportDelim, , "tbl受注", "受注.CSV" ts_Watch "CSVエクスポート(DoCmd)" 'テストパターン3 DoCmd.TransferText acExportHTML, , "tbl受注", "受注.HTM" ts_Watch "HTMLエクスポート" 'テストパターン4 lngFileNum = FreeFile() Open "受注.CSV" For Output As #lngFileNum Set dbs = CurrentDb Set rst = dbs.OpenRecordset("tbl受注") With rst Do Until .EOF Print #lngFileNum, !受注コード & "," & !商品コード & "," & _ !単価 & "," & !数量 & "," & !割引 .MoveNext Loop .Close End With Close #lngFileNum ts_Watch "CSVエクスポート(Print #)" Next iintLoop End Sub DoCmdオブジェクトのメソッドを使った方法については、文法に沿ってメソッドや引数を指定して、1行の命令によってそれぞれのパターンを実行します。 またPrint #ステートメントを使った方法については、DAOを使ってテーブルを開き、1件ずつ読み込みながら、CSV形式になるようカンマを付けた文字列を組み立てて、それをテキストファイルに書き出しています。今回は特にフォーマットの変換などはなく、テーブルに保存されているデータをそのまま出力しています。 いずれの方法についても、ループで10回処理し、その合計時間等を確認してみます。なお、テーブル「tbl受注」には5万件のレコードが保存されています。この数字は、出力したファイルをExcelで読み込む際、その読み込み可能最大行数(約6万数千)を意識したものです。 そして、そのテスト結果は次のようなものになりました。いずれも単位は秒です。 まずExcelワークシート形式にエクスポートする方法ですが、ワークシートの内部構造がどのようなものか分かりませんが、Accessのテーブルからそのような複雑そうな形式に変換するわけですから、その処理時間に時間を要するのではと推測していたのですが、実際にはDocmdオブジェクトの中では最も、しかもかなり速く処理されることが分かりました。単純な形式であるCSVファイルの半分以下の処理時間です。どうやら複雑そうに思えるExcelワークシートの構造も、Accessからみれば比較的近い形の構造となっているのかしれません。そして、AccessにとってはCSVというテキスト形式に変換することの方が苦手なのかもしれません(これはAccessというよりTransferTextメソッドの能力の問題かもしれませんが....)。 また、HTMLファイル形式への出力についても、Excelワークシートにはかなり劣るものの、CSVファイルより優っているというのも意外でした。HTML形式の場合、データを区切るためのHTMLタグが入るため、出力するデータ量そのものはCSVより多くなっています。単純に書き込み量だけみればCSVの方が速そうなのですが、結果はそうはなっていません。 一方、Print #ステートメントを使った方法は抜群の結果が出ているといえます。DocmdオブジェクトのTransferTextメソッドと同じ内容のファイルが作られているにもかかわらず、一方はExcelワークシートより倍以上遅く、一方は倍近く速いという意外な結果です。CSVファイル出力どうしを比較すると、DocmdオブジェクトとPrint #ステートメントとでは4倍近い開きがあります。この結果に対する理由は明確ではありませんが、マクロを使ったりDocmdの命令1行で済ませずに、細かいVBAのコードを数行書くことを惜しまなければ、それ相応のパフォーマンスが得られることは確かです。 Accessの場合、エクスポートできる外部ファイルの形式は他にもいろいろありますが、今回行ったテストの範疇では、次のような順位付けができると思います。
さて、上記テストの結果、Print #ステートメントを使った方法は、プログラムのコードを書くのは少々長く面倒ですが、パフォーマンス面ではなかなか使えるということが分かりました。そこで、これを応用することでさらに速く処理できないかということで、次のようなコードを考えてみました。ここでのポイントは、外部のテキストファイルに実際にデータを書き出す命令、すなわちPrint #ステートメントの実行を1回だけに抑えている点です。テーブルからの読み込み処理のループ内では個々に書き出しは行わず、ひたすらstrOutPutという文字列変数にそのデータを付け加えていきます。そしてループを抜けたところで一気にそれを書き出そうというものです。 Sub CSVTest2() Dim dbs As Database Dim rst As Recordset Dim lngFileNum As Long Dim strOutPut As String lngFileNum = FreeFile() Open "受注.CSV" For Output As #lngFileNum Set dbs = CurrentDb Set rst = dbs.OpenRecordset("tbl受注") With rst strOutPut = "" Do Until .EOF strOutPut = strOutPut & !受注コード & "," & !商品コード & "," & _ !単価 & "," & !数量 & "," & !割引 & vbCrLf .MoveNext Loop .Close End With Print #lngFileNum, strOutPut Close #lngFileNum End Sub このプログラムの実行結果ですが、実際にやってみると、ループなしのたった1回の処理にもかかわらず、その終了を待ち切れずに途中で強制中断させてしまうほど時間がかかるということが分かりました。ファイルへの出力というと、ハードディスクを物理的に動かす書き出し処理に時間がかかるのではと思っていたのですが、実際には、長い文字列の演算を行う方がよほど時間を要するということのようです。「Print #ステートメントを使う際には短く刻んで出力していった方がよい」ということは明らかでした。 |
|||||||||||||||||||||||||||
|
Copyright © T'sWare All rights reserved |