Excelオートメーションのパフォーマンスを改善するために何ができるのかと思っていました。
ここに私が自分自身を見つけたいくつかがあります:
_ExcelApp.ScreenUpdating = false
_-画面の再描画をオフにします
_ExcelApp.Calculation = Excel.XlCalculation.xlCalculationManual
_-セルの値が変更されたときにExcelが自動的に再計算しないように計算エンジンをオフにします(完了後に再びオンにします)
Worksheet.Cells.Item(row, col)
および_Worksheet.Range
_への呼び出しを減らします-必要なセルを見つけるために、数百のセルをポーリングする必要がありました。セルの場所のキャッシュを実装することで、実行時間が約40秒から約5秒に短縮されました。
どのような相互運用呼び出しはパフォーマンスに大きな影響を与えるので、避ける必要がありますか?不要な処理が行われないようにするために、他に何ができますか?
C#またはVB.Netを使用して範囲を取得または設定する場合、範囲の合計サイズを把握し、1つの大きな2次元オブジェクト配列を取得します...
//get values
object[,] objectArray = shtName.get_Range("A1:Z100").Value2;
iFace = Convert.ToInt32(objectArray[1,1]);
//set values
object[,] objectArray = new object[3,1] {{"A"}{"B"}{"C"}};
rngName.Value2 = objectArray;
オブジェクト配列から型を元に戻すときに自動的にこれを行うわけではないため、Excelが保存しているデータ型(テキストまたは数値)を知っていることが重要です。事前にデータのタイプを確認できない場合は、必要に応じてテストを追加してデータを検証します。
これは、db結果セットからExcelシートにデータを入力するのが最善の方法であると考えている人向けです。これは決して完全なリストではありませんが、いくつかのオプションをリストします。
古いPentium 4 3GHzボックスで155列と4200レコードでExcelシートにデータを取り込む際のパフォーマンスの数値には、最も遅いものから最も速いものの順に10秒を超えないデータ取得時間が含まれます...
一度に1つのセル-わずか11分未満
Htmlに変換してデータセットを作成+ htmlをディスクに保存+ htmlをExcelに読み込み、ワークシートをxls/xlsxとして保存-5分
一度に1列-4分
非推奨のSQL 2005のsp_makewebtaskプロシージャを使用してHTMLファイルを作成する-9秒+ HTMLファイルをExcelにロードし、XLS/XLSXとして保存する-約2分
.NetデータセットをADO RecordSetに変換し、WorkSheet.Range []。CopyFromRecordset関数を使用してExcelにデータを入力します-45秒!
私はオプション5を使用することになりました。これが役立つことを願っています。
可能な場合は、Excelの組み込み機能を使用します。たとえば、列全体で特定の文字列を検索する代わりに、GUIでCtrl-Fを使用してfind
コマンドを使用します。
Set Found = Cells.Find(What:=SearchString, LookIn:=xlValues, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not Found Is Nothing Then
Found.Activate
(...)
EndIf
一部のリストを並べ替える場合は、Excel sort
コマンドを使用します。VBAでは手動で並べ替えないでください。
Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
多くのセルの値をポーリングしている場合、範囲内のすべてのセル値をバリアント配列に一度に取得できます。
Dim CellVals() as Variant
CellVals = Range("A1:B1000").Value
ここでは、値を取得する範囲のサイズに関してトレードオフがあります。 1000個以上のセル値が必要な場合、これはおそらく、異なるセルをループして値をポーリングするよりも高速です。
パフォーマンスは、Excelの自動化方法にも大きく依存します。 VBAは、COMオートメーションよりも高速です。NETオートメーションよりも高速です。また、通常、早期(コンパイル時)バインディングは遅延バインディングよりも高速です。
深刻なパフォーマンスの問題がある場合は、コードの重要な部分をVBAモジュールに移動し、そのコードをCOM/.NETオートメーションコードから呼び出すことを検討できます。
.NETを使用する場合は、Microsoftから入手可能な最適化されたプライマリ相互運用機能アセンブリも使用する必要があり、カスタムビルドの相互運用機能アセンブリは使用しないでください。
Anonymous Typeが言うように、大きな範囲のブロックの読み取り/書き込みはパフォーマンスにとって非常に重要です。
COM-Interopのオーバーヘッドが依然として大きすぎる場合は、最速のExcelインターフェイスであるXLLインターフェイスの使用に切り替えることができます。
XLLインターフェイスは主にC++ユーザーを対象としていますが、XL DNAとAddin Expressの両方は、COM-Interopよりも大幅に高速な.NETからXLLへのブリッジ機能を提供します。
VBAでできるもう1つの大きなことは、Option Explicitを使用し、可能な限りVariantを避けることです。 VBAではバリアントを完全に回避することはできませんが、実行時にインタープリターにより多くの作業を行わせ、メモリを浪費させます。
ExcelでVBAを使い始めたとき、この記事は非常に役に立ちました。
http://www.ozgrid.com/VBA/SpeedingUpVBACode.htm
そしてこの本
http://www.Amazon.com/VB-VBA-Nutshell-Language-OReilly/dp/1565923588
に似ている
app.ScreenUpdates = false //and
app.Calculation = xlCalculationManual
あなたも設定できます
app.EnableEvents = false //Prevent Excel events
app.Interactive = false //Prevent user clicks and keystrokes
ただし、最初の2つほど大きな違いはないようです。
範囲の値を配列に設定するのと同様に、列のすべての行に同じ式を持つテーブルがほとんどのデータで作業している場合、式にR1C1式表記を使用して、設定する式文字列に等しい列全体を設定できますすべてを1回の呼び出しで。
app.ReferenceStyle = xlR1C1
app.ActiveSheet.Columns(2) = "=SUBSTITUTE(C[-1],"foo","bar")"
また、ExcelDNA&.NET(またはCの難しい方法)を使用してXLLアドインを作成することも、UDFを複数のスレッドで実行できる唯一の方法です。 (Excel DNAのExcelFunction属性のIsThreadSafeプロパティを参照してください。)
Excel DNAに完全に移行する前に、VBAプロジェクトで参照するCOM可視ライブラリを.NETで作成することも試しました。重いテキスト処理は、VBAのコレクションの代わりにラップされた.NETリストクラスを使用するように、VBAよりも少し高速ですが、Excel DNAの方が優れています。