少し前に、同僚と私は、外部アプリケーションコードから直接DMLコマンド(選択/挿入)を呼び出すことによって、またはデータベースストアドプロシージャを使用する方がよい方法で、データをすばやく選択して書き込む方法について少し理論的な議論をしました。 Oracle DBを使用して1つのプロジェクトのチームに参加したとき、この論争は実用的な面に成長しました。 偶然ではなく、プロバイダー同士を比較するだけでなく、データベースを操作するためのさまざまなアプローチを確認するテスト結果に焦点を当てることを決定しました。
Googleの最初の2ページでは、テスト参加者を特定しました。
- Oracle ODP.NET
- Devart dotConnect for Oracle
ご覧のとおり、選択肢は豊富ではありませんが、オプションが少ないほど選択が容易です。
プロバイダーの機能はほぼ同じです。 Devartソリューションの利点の中には、単純なトランザクション(接続クラスにメソッドが組み込まれている)での作業が少し簡単であり、Oracleクライアントがインストールされていなくても動作する機能(いわゆるダイレクトモード)があります。 また、DevArtに有利なのはパフォーマンステストの存在です。このテストでは、dotConnect for Oracle(OraDirect)が競合他社を肩代わりさせます(
結果を参照 )。
プロジェクトの基礎は(将来的に)かなりのクライアント負荷を持つサーバーになることであったため、このプロバイダーまたはそのプロバイダーがもたらすオーバーヘッドコストを評価することは興味深いものでした。
紛争については、私の同僚は、10個の挿入で匿名スクリプトを実行することと、これらの10個の挿入を実行するパラメーターを渡すストアドプロシージャを呼び出すこととの間に大きな違いはないと主張しました。 データサンプリングでも同様です。直接選択することも、refカーソルなどを返す関数を呼び出すことも違いはありません。 ストアドプロシージャの明確な優位性を提唱しました。
さて、私たちは科学的アプローチのためです! したがって、選択と挿入をテストするためのテーブル構造を作成し、できるだけ現実に近い状態でテスト用のコードを記述し、開始します...
すべてのテストは2つのグループに分けられました。
- 4つのテーブルの選択:1つのマスターテーブルと3つの詳細テーブル(反復ごとに合計22行)。 データはすぐにIDataReaderからフェッチされ、さらなる作業のためにDataTableに追加されます。
- 各選択は、個別のコマンドによって実行されます。
- バッチプロシージャが呼び出され、入力でマスターテーブルの主キーを取得し、出力で(各テーブルに)4 refカーソルを返します。
- 2つのテーブルへのデータの書き込み:マスターの1行と、トリガーによって生成されたマスターテーブルからレコードの一意の識別子を返す詳細な8行。
- 9つの挿入すべてが順番に実行されます。
- 1つのコマンドは、すべての実行可能挿入を含む事前生成された匿名PL / SQLブロックで実行されます。
- バッチ関数が呼び出され、マスターテーブルのパラメーターがそのまま転送され、詳細テーブルのパラメーターが1次元の連想配列の形式で転送されます。
- 配列バインディングを使用して、詳細テーブルにレコードを繰り返し挿入しました
dotConnectについては、Oracleクライアントを介した作業と直接アクセスの両方のオプションをテストしました。 すべてのテーブルの統計が収集されました。 各実行の前に、スクリプトを使用して、挿入のテストに使用されたテーブルがクリアされました。
truncate table <detail> drop storage; alter table <detail> modify constraint foreignkey01 disable; truncate table <master> drop storage; alter table <detail> modify constraint foreignkey01 enable;
各テストは5回実行され、それぞれ100,000回反復されました。 もちろん、より多くの反復回数のテストがありましたが、5000から始まって、結果は非常に似たものになりました...
更新する
最初の結果と結論は、ODP.NETが厄介なエラーのために利点を与えられたという事実のために不正確であることが判明しました。
履歴の誤った結果を保存しますまず、dotConnect for Oracleは例外なくすべてのテストを失いました。 また、selectの場合、さまざまなエラーと実験の一般的な欠陥に起因する2%から11%の遅い場合、挿入の場合、結果は単に悲惨です:61%から227%遅くなります! また、dotConnectのダイレクトモード自体はOCIモードよりもやや遅いことが判明したため、ODP.NETとの比較には関与していなかったことにも注意してください。
100,000回の反復のテストから得られた平均値を以下の表に示します。 ミリ秒単位の時間。
テストの説明 | dotConnect OCIモード | dotConnectダイレクトモード | ODP.NET |
---|
ミリ秒 | % | ミリ秒 | % | ミリ秒 | % |
---|
選択:順次実行 | 167267 | 111% | 194648 | 129% | 150563 | 100% |
選択:バッチプロシージャコール | 147084 | 102% | 161508 | 112% | 144499 | 100% |
挿入:順次実行 | 217352 | 161% | 207536 | 154% | 134956 | 100% |
挿入:匿名のPL / SQLブロックを呼び出す | 154241 | 182% | 152470 | 180% | 84572 | 100% |
挿入:バッチ関数の呼び出し | 98528 | 327% | 105318 | 350% | 30088 | 100% |
結論は簡単です:
- パフォーマンスはそれほど重要ではないが、最大限の移植性が必要な場合は、dotConnectを購入してダイレクトモードで使用してください。 小さなプロジェクトには本当に便利です。
- 最大のパフォーマンスを得るには、ODP.NETを使用します。 オプションなし。
- 原則として、データのサンプリングは好きなように行うことができます。 しかし、ミリ秒ごとに実際にカウントする場合は、ストアドプロシージャを呼び出す方が有益です。このプロシージャは、フェッチの準備がすでに整っているいくつかのカーソルを返します。
- データ挿入に関しては、ODP.NETを使用する場合のストアドプロシージャが他の方法と比較して3x4倍のゲインを提供することは明らかです。 このアプローチは、型宣言を含むすべてのコードが1つのPL / SQLパッケージに集中しているため、将来的に編集とバージョン管理が容易になるという点で便利です。
また、新しい結果には、配列バインディングを使用してレコードを挿入するためのテストが含まれています(アイデアについては
VladVRに感謝し
ます )。
DotConnectは通常、ODP.NETよりも低速のままでした。2%から11%のデータをフェッチするとき、ストアドプロシージャと配列バインディングを使用して貼り付けるときは3%から19%でした。 しかし同時に、insert'ovのシーケンシャルコール中にレコードを挿入し、匿名のPL / SQLスクリプトを使用すると、ODP.NETよりも高速であることが判明しました(8%〜14%)。
ダイレクトモードdotConnectは、レコードの順次挿入、残りを7〜8%で決定する1つの分野でのみ有効です。 しかし、多くの制限があるため、実際のオプションとは見なされませんでした。
100,000回の反復のテストから得られた平均値を以下の表に示します。 ミリ秒単位の時間。
テストの説明 | dotConnect OCIモード | dotConnectダイレクトモード | ODP.NET |
---|
ミリ秒 | % | ミリ秒 | % | ミリ秒 | % |
---|
選択:順次実行 | 167267 | 111% | 194648 | 129% | 150563 | 100% |
選択:バッチプロシージャコール | 147084 | 102% | 161508 | 112% | 144499 | 100% |
挿入:順次実行 | 193374 | 107% | 181218 | 100% | 196228 | 108% |
挿入:匿名のPL / SQLブロックを呼び出す | 126916 | 100% | 128962 | 102% | 144762 | 114% |
挿入:バッチ関数を呼び出す | 83692 | 119% | 94004 | 133% | 70580 | 100% |
挿入:配列バインディング | 87258 | 103% | 90308 | 107% | 84406 | 100% |
GlukKazanとの議論に続いて、各トランザクションの後にコミットなしでテストも行われました。 彼らは全体像を変えなかった-前進の相対的な割合だけが変わった。
GitHubのExcelファイルの完全なテスト結果
結論はそれほど変わっていません。
- パフォーマンスを最大にするには、ODP.NETを引き続き使用する必要があります。
- ODP.NETが十分でない場合、たとえば、実際に各行のrefカーソルを返すリクエストで関数を呼び出す必要がある場合、dotConnectを使用します。
- 原則として、データのサンプリングは好きなように行うことができます。 しかし、ミリ秒ごとに実際にカウントする場合は、ストアドプロシージャを呼び出す方が有益です。このプロシージャは、フェッチの準備がすでに整っているいくつかのカーソルを返します。
- データの挿入に関して、両方のプロバイダーを使用する場合の最適なオプションは、ストアドプロシージャを呼び出すことです。 この場合のDotConnectは、運命を決定したODP.NETよりも19%遅く実行されます。 また、このアプローチは、型宣言を含むすべてのコードが単一のPL / SQLパッケージに集中しているため、将来編集およびバージョン管理が容易になるという点でも便利です。
したがって、このプロジェクトではODP.NETを選択し、ストアドプロシージャを使用してデータを送受信します。 まあ、同僚がジュースを求めて走らなければならなかったので、後で一緒に飲みました。
回路オブジェクトを作成および入力するためのスクリプト、更新されたプロジェクトコード(C#、VS.2013)、および詳細なテスト結果は
GitHubで入手でき
ます。PS:Oracleバージョン11.2.0.4、ODP.NET Managed 4.121.2.0、DevArt dotConnect for Oracle Trial 8.4.359.0