アプリケーションとTimesTenデータ・ストアのパフォーマンスを最大にする方法については、TimesTenの開発者ガイドのアプリケーションのチューニングに関する章を参照してください。この項では、パフォーマンスを低下させる、より一般的な問題を検出する方法について説明します。
クライアント/サーバー接続では、TimesTenにかなりのパフォーマンスのオーバーヘッドが加わります。また、ドライバ・マネージャ接続でも、ある程度パフォーマンスに影響を与えます。最大限のパフォーマンスを得るには、クライアント/サーバー接続ではなく、TimesTenデータ・ストアに直接接続します。クライアント/サーバー接続の場合は、データ・ストアとのすべての通信にネットワーク待機時間が伴うため、かなりのパフォーマンスのオーバーヘッドが発生する可能性があります。
データ・ストアをホスティングしているマシンとは別のマシンでアプリケーションを実行する必要がある場合は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のクライアント/サーバーのチューニングに関する説明を参照してください。
通常、TimesTen問合せオプティマイザには、効率的な問合せ計画を選択する大変優れた機能があります。ただし、効率的な計画を選択するには、複雑な問合せに含まれる表に関する追加情報が必要となります。
オプティマイザが効率的な計画を選択するには、データベース統計を使用する必要があります。表について、行の数と列の値のデータ分布を把握することにより、オプティマイザはより高い確率で、その表にアクセスするための効率的な問合せ計画を選択できます。
TimesTen表にアクセスする問合せを準備する前に、ttOptUpdateStatsプロシージャを使用して、その表の統計を更新できます。表の統計を更新する場合は、表にデータをロードしてから問合せを準備するまでの間に統計を更新すると、最高の結果が得られます。たとえば、データを移入する前に表の統計を更新すると、表に行がない(または小数の行しかない)ものとして、問合せが最適化されます。その後、数百万行のデータを表に移入してから問合せを実行すると、表にほとんど行がない状況で適切に動作した計画は非常に遅くなります。
統計の更新の詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTen問合せオプティマイザに関する説明を参照してください。
ODBCのデフォルトでは、データ・ストアへのすべての接続で自動コミットが有効になっています。つまり、個々のSQL文は独自のトランザクションでコミットされます。
ほとんどの場合、SQL_AUTOCOMMIT_OFFを指定してSQLSetConnectOptionファンクションをコールし、自動コミットを無効にして、1つのトランザクションで複数のSQL文を明示的にコミットすることによって、アプリケーションのパフォーマンスを改善できます。これは、特にバルク挿入やバルク削除のような大規模な操作で有効です。
ただし、単一のトランザクションにあまりにも多くの操作を含めると、ロックが長時間保持されるため、システム全体の同時実行性が低下するおそれがあります。通常、バルク挿入/更新/削除の操作は、数千行ごとにコミットすると、最も効率よく処理できる傾向があります。
DurableCommitsのデフォルトの設定はOFFです。DurableCommitsがONの場合、メモリーに保持されているすべてのトランザクション・ログ・レコードが、トランザクションのコミット手順の一部として、ディスクに書き込まれます。これは、トランザクションがリカバリ可能であることを保証するための簡単な方法です(ただし、実際のディスク障害が発生した場合を除きます)。
DurableCommitsのデフォルト設定(OFF)では、ほぼすべてのアプリケーションのパフォーマンスが改善されます。DurableCommitsがON(DurableCommits=1)の場合は、トランザクションのコミットのたびに、物理ディスクI/Oの同期コストが発生します。これは、書込みの多いアプリケーションの場合、処理速度の遅いディスク・サブシステムを常時待機するため、TimesTenは最大の速度で処理できないことを意味します。つまり、TimesTenの処理速度が従来のデータベースよりわずかに速いだけになる場合もあります。DurableCommitsがOFFの場合は、物理ディスクI/Oは非同期処理となり、複数の更新が一括して同時にディスクに書き込まれるので、ディスクのボトルネックを回避できます。ディスクI/Oを非同期処理にすることで、パフォーマンスは最大になりますが、トランザクションが消失する可能性もあります。
わずかな数のトランザクションの消失であれば許容できる場合は、DurableCommitsをOFFに設定したままにしておき、次のいずれかのメカニズムを使用して、トランザクションが消失する可能性を詳細に管理します。すべてのトランザクションがリカバリ可能であることを保証する必要がある場合は、TimesTenレプリケーションを実装します。
次のメカニズムによって、リカバリ可能性の点からのシステム障害の影響を詳細に管理できます。
ttDurableCommitをコールする頻度が低すぎると、パフォーマンスが不安定になり、永続性が低下する可能性があります。これに対し、ttDurableCommitをコールする頻度が高すぎると、アプリケーションでのI/Oが多くなり、パフォーマンスが低下する可能性があります。間隔が適切であれば、パフォーマンスは安定し、適切な永続性が得られます。
永続コミットの詳細は、次の説明を参照してください。
最高のパフォーマンスを得るには、複数回実行するSQL文をすべて事前に準備しておく必要があります。これはすべてのリレーショナル・データベースにあてはまります。ただし、TimesTenをきわめて高速なトランザクション率で使用する場合、文のコンパイルに必要な時間が、文の実行に必要な時間の数倍に達する可能性もあります。このため、文を準備していないアプリケーションでは、TimesTenのパフォーマンスが大幅に悪化する可能性があります。文の事前準備に加えて、それらの入力パラメータと出力列も事前にバインドしておく必要があります。
文の準備の詳細は、『Oracle TimesTen In-Memory Database C開発者およびリファレンス・ガイド』の文の事前準備に関する説明を参照してください。
アプリケーション設計によっては、データをロードした後にTツリー索引を作成すると、データのロードに要する時間を最小化できます。この場合、次の順序で操作を実行する必要があります。
詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTen問合せオプティマイザに関する説明を参照してください。
データベースのパフォーマンスを向上させるために、どのような索引をどれくらい作成すればよいのかを判断するのは重要なことです。作成した索引が少なすぎると、頻繁に行うデータベース操作の一部が通常よりも遅くなります。作成した索引が多すぎると、索引の更新に余分な時間が必要になるために、挿入/更新/削除の操作に通常よりも時間がかかります。また、表に含まれる索引が多すぎると、内部デッドロックが発生する場合があります。
索引には、『Oracle TimesTen In-Memory Database概要』の索引付けテクニックに関する説明で示されているように、次の2つのタイプがあります。
ハッシュ索引は、表の主キーに対して自動的に作成され、完全一致(=)検索ではTツリー索引よりも高速です。最高のパフォーマンスを得るには、CREATE TABLE文のPAGESパラメータを使用して、ハッシュ索引のサイズを正しく設定する必要があります。ハッシュ索引のサイズが適切でないと、問合せのパフォーマンスが低下します。
ハッシュ索引のページ数を決定する計算式は、次のとおりです。
expected_number_of_rows / 256
xyz.product表に100,000行を含める場合、100,000/256 = 390ページという式を使用して、主キー(prod_num)のハッシュ索引のサイズを決定できます。
CREATE TABLE xyz.product (
prod_num INTEGER NOT NULL PRIMARY KEY,
name VARCHAR(40) NOT NULL,
price DECIMAL10,2) NOT NULL,
ship_weight FLOAT NOT NULL,
description VARCHAR(255) NULL,
picture VARBINARY(10240) NULL,
notes VARCHAR(1024) NULL
)
UNIQUE HASH ON(prod_num) PAGES=390;
ハッシュ索引のサイズを変更するには、ALTER TABLE文とともにSET PAGES=CURRENT句を使用します。
CREATE INDEX文を使用して、Tツリー索引を作成します。Tツリー索引は、完全一致検索および範囲検索(>、<、BETWEEN)に最適です。ハッシュ索引とは異なり、Tツリー索引はサイズ設定が不要で、表に影響を及ぼすことなく作成および削除できます。
たとえば、xyz.product表のprod_num列に、Tツリー一意索引xyz.ProdNumIndexを作成するには、次のように入力します。
CREATE UNIQUE INDEX xyz.ProdNumIndex
ON xyz.product (prod_num);
TimesTenの表と索引のスキーマを設計する際に、考慮すべき問題がいくつかあります。
次の問合せについて考えてみます。
SELECT ... FROM t1 WHERE col1 = ? AND col2 = ?
例2.5から例2.8は、異なる4種類の索引構成例ですが、それぞれの例で、オプティマイザがこの問合せについてどの索引を選択するかを示しています。
t1
に次の2つの索引が存在します。
この場合、いずれの索引もこの問合せへの応答に使用できます。
WHERE句の列がハッシュ索引の列と完全に一致するため、ハッシュ索引を使用できます。また、WHERE句の列がTツリー索引の列の先行接頭辞(最初の2つ)であるため、Tツリー索引を使用して問合せに応答できます。
TimesTenオプティマイザはハッシュ索引を選択します(ハッシュ索引の方が高速なため)。
t1
に次の2つの索引が存在します。
この場合、Tツリー索引のみをこの問合せへの応答に使用できます。
ハッシュ索引の列の1つ(col3
)が問合せのWHERE句に指定されていないため、ハッシュ索引は使用できません。ただし、Tツリー索引の列は、問合せのWHERE句の列と完全に一致します。
TimesTenオプティマイザはTツリー索引を選択します。
t1に次の2つの索引が存在します。
この場合、ハッシュ索引のみをこの問合への応答に使用できます。
ハッシュ索引のすべての列が問合せのWHERE句に含まれるため、ハッシュ索引を使用できます。ただし、問合せのWHERE句に追加の列があるため、問合せの結果が返される前に、ハッシュ索引から読み込まれるすべての行に、col2 = ?
条件が適用されます。
TimesTenオプティマイザはハッシュ索引を選択します。
t1
に次の2つの索引が存在します。
ハッシュ索引: (col1
, col2
, col3
)
Tツリー索引: (col3
, col1
, col2
)
この場合、いずれの索引もこの問合せへの応答に効率的には使用できません。ただし、Tツリー索引は全表スキャンに使用できます。
前述の例2.6と同じ理由で、ハッシュ索引は使用できません。問合せの列(col1
, col2
)が索引の先行接頭辞ではないため、Tツリー索引は使用できません。
いずれの索引も使用できないため、データベースは表スキャンを実行して問合せに応答する必要があります(一時索引を作成する場合もあります)。これによって、パフォーマンスが低下します。
前述の4つの例からわかるように、最も頻繁に行われるデータベースへの問合せに基づいて、どの索引を作成するかを慎重に選択する必要があります。
適切な索引の作成の詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のハッシュ索引またはツリー索引の適切な選択に関する説明を参照してください。
複数のアプリケーションがどのようにデータ・ストアに同時アクセスするかで、パフォーマンスが大きく影響を受けることがあります。
アプリケーションは、データ・ストア全体、個々の表および個々の行に対してロックを取得できます。それとは別に、トランザクションがコミットまたはロールバックするまで読取りロックや更新ロックを保持するかどうかを決定する分離レベルも設定できます。
「デッドロックとタイムアウトを確認する」で説明するように、SYS.MONITOR表を確認するか、またはttXactAdminユーティリティを使用して、アプリケーションがロックの待機に時間を費やしているかどうか検出できます。ロックの競合が激しい場合は、次のように実装することによって、システム全体のパフォーマンスを改善できる場合があります。
ロックの競合を最小になるように前述のとおり設定しても、多数の競合が発生する場合は、競合がアプリケーション自体に関係している可能性もあります。たとえば、同時実行のスレッドが、繰り返し同じ行にアクセスしているような場合です。このような競合の検出には、ttXactAdminユーティリティが役立つことがあります。また、このような状況では、トレースが有効なこともあります。
詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の並行性制御に関する説明を参照してください。
サード・パーティのデータベース・インタフェース・パッケージの多くは、データベースのパフォーマンスを低下させます。これらのインタフェースを使用できるのは、特定のアプリケーションにおけるパフォーマンスは重要ではなく、ユーザーにとってパフォーマンスよりも必要な条件がある場合です。
これらのサード・パーティのパッケージは低速である可能性があるため、TimesTenでは、TTClassesという独自のC++ ODBCラッパーが開発されました。これは、TimesTenに付属されています。TTClassesの詳細は、『Oracle TimesTen In-Memory Database TTClassesガイド』を参照してください。
TimesTenでは、メモリー・リークの発生箇所の検出に、Purifyを使用することをお薦めします。
注意: | 使用中またはリークしている実メモリーが多くない場合、処理速度が大幅に低下することはありません。処理速度の低下は、RAMの使用量が、システム上で使用可能なRAMを超えたときに発生します。 |
アプリケーションにはTimesTenライブラリがリンクされるため、アプリケーションでPurifyを実行すると、TimesTenライブラリも検証対象となります。わずかな数ですが、TimesTenライブラリには、Purifyによって検出される警告があることが予想されます。このような警告は、抑制ファイル(テクニカル・サポートから入手可能)を使用することで、表示されないようにできます。
抑制ファイルの名前はsuppress.purify
です。これを使用するには、PURIFYOPTIONS環境変数に次の行を追加します。
-add-suppression-files='_path_/suppress.purify'
プロセスによってメモリーがリークしているかどうかを判断するには、OSのユーティリティを使用して、プロセスで使用中のメモリー量を監視できます。通常、このようなユーティリティを使用すると、各プロセスのサイズがデータ・ストアの共有メモリー・セグメントのサイズとともにレポートされます。各プロセスによって大量のメモリーが使用されているようにレポートされる場合がありますが、このメモリーのほぼすべてが共有されていることに注意してください。このため、合計サイズは重要ではありません。
TimesTenでメモリー・リークを検出した場合、その多くは実メモリー・リークではなく、リークの測定方法の問題です。メモリー・リークを識別するには、ほとんどのオペレーティング・システム・ユーティリティ(topなど)は有効ではありません。TimesTenでは、共有メモリー・セグメントを使用するため、実行時にメモリーの追加ページが影響を受ける可能性があります。
Purifyでは、TimesTen内のメモリー・リークの一部を検出できますが、これらは1回で割り当てられ、再発生することはありません。SQLAllocEnvへのコールを繰り返すと、それ以上割当ては発生しません。そのため、固定サイズのオーバーヘッドとして表示されます。次の出力例に、Purifyによって検出されるTimesTenのメモリー・リークを示します(最初の値がリーク・サイズで、2つ目の値はリークの数です)。
次のリークは、スレッドごとに1回割り当てられます。このように、スレッドを明示的に作成した場合、このスレッドは終了時に解放されます。Solarisでは、非スレッド・プログラムは、スレッドが1つのスレッド・プログラムに変更されます。ただし、Solarisでは、単一のスレッドはプロセスの終了時に適切にクリーンアップされないため、このスレッドは解放されません。
1064 1 0x22308 vsInitaliseNativeThreadDataForThread <
vsInitaliseThreadDataForThread < vsProcessInitalisation < vsUnixProcessAttach < SQLAllocEnv <main
次のリークは、プロセスごとに1回割り当てられます。
588 1 0x220a0 vsInitaliseThreadDataForThread <
vsProcessInitalisation < vsUnixProcessAttach < SQLAllocEnv < main
次のリークは、Solarisによってプロセスごとに1回、thr_setspecific()に内部的に割り当てられます。OSでは、プロセスの終了時にこのリークがクリーンアップされることはありません。このリークを回避する方法はありません。
8 1 0x218c0 calloc < _ti_pthread_setspecific <
vsInitaliseThreadDataForThread < vsProcessInitalisation < vsUnixProcessAttach < SQLAllocEnv <main
次のリークは、Solarisによってプロセスごとに1回、thr_setspecific()に内部的に割り当てられます。OSでは、プロセスの終了時にこのリークがクリーンアップされることはありません。このリークを回避する方法はありません。
1 0x218e0 realloc < _ti_pthread_setspecific <
vsInitaliseThreadDataForThread < vsProcessInitalisation < vsUnixProcessAttach < SQLAllocEnv <main
ttTraceMon -e show(「ttTraceMonユーティリティの使用」を参照)を使用して、すべてのTimesTenコンポーネントに対してトレースが無効(OFF)になっていることを確認します(ERRは1に設定され、他のすべてのコンポーネントは0に設定されている必要があります)。
Windowsの場合、ODBCトレースが無効になっていることを確認します。コントロール・パネルで「ODBC」をダブルクリックして、ODBCデータソース・アドミニストレータを開きます。「トレース」タブを選択して、トレースが無効になっていることを確認します。
マテリアライズド・ビューのチューニングが適切でないと、パフォーマンスに大きな影響を与える可能性があります。詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のマテリアライズド・ビューのパフォーマンスの影響に関する説明、およびマテリアライズド・ビューのパフォーマンスの改善に関する説明を参照してください。
表の作成時、パーティションは1つです。ALTER TABLE ADDを使用して新しい列を追加すると、新しいパーティションが表に追加されます。1回のALTER TABLE ADD文で複数の列を追加した場合、追加されるパーティションは1つのみです。
表当たりのパーティション数の制限は255です。この数を超えると8204エラーが生成されます。ただし、新しいパーティションを表に追加するたびに不要な読取りが発生し、表に追加された列に対する問合せパフォーマンスがわずかに低下することに注意してください。
各表のパーティション値は、システム表SYS.TABLESの列SYS16で追跡されます。表のパーティション数は、次の問合せで取得できます。
SELECT tblname, sys16 FROM SYS.TABLES;
表に含まれるパーティションが多すぎることが検出された場合は、表を再作成するか、ttMigrate create(-c -noRepUpgrade)の後にttRestore(-r -noRepUpgrade)を使用して、表を保存およびリストアすることができます。ALTER TABLE DROPでは、表からパーティションは削除されません。