Oracle Real Application Clusterの検証 その7
<Oracle Real Application Clusterの検証 ~その7~>
ペンネーム ダーリン
— RAC環境でのチューニング —
さてさて、先週はスケラービリティ向上を目指すためのチューニングを行う
ために、インデックスにターゲットを絞りました。
で、具体的にどのような方法を考えたかと言うと、
・各インスタンス間での競合を防ぐために、インスタンス毎でインデックス
のブロックが使用されるようにする。
・大量のトランザクションにおける、インデックスリーフブロックの競合自
体を防ぐ。
という感じです。
<>
ログ系のインデックスのカラムには、先週お話したとおりログの登録日時が
使用されていました。これは、トランザクションの状況を確認する検索系の
システムの要求仕様を満たすために必要なものでした。いつ、どれくらいの
新規登録や、更新などが行われたか、どの時間帯に誰が処理しているかと言
った情報を集計するためです。
このため、同じようなことをしたがる人はどこにでも居るので、どうしても
ログレコードをインサートすると、インデックスの最新ブロックが競合を起
こしてしまいます。
まずは簡単なところに目をつけました。
日時カラムの前に、各インスタンスのインスタンス番号を追加してあげるこ
とで、これを解消することが出来ると考えられます。
なぜか?B-TREEインデックスは、キー項目を範囲によってブランチ、リーフ
と言ったブロックに分割して管理します。よって、インデックスを構成する
カラムの先頭にインスタンスを識別するカラムがあると、それらのインデッ
クスブロック(ブランチ、リーフ)は、それぞれのインスタンスにのみ存在
する可能性が高くなっています。
もちろん、各インスタンスで検索した場合は、インスタンス間を飛び交うこ
とになりますが、インサート時の(例えば”ITL waits”のような)待ちは解消
できると考えられます。
カラムの構成はこんな感じです。
SQL> desc logtbl1 名前 NULL? 型 ----------------------- -------- ------------------- NODE_NO NUMBER(2) INS_DATE TIMESTAMP(6) CONNECT_ID CHAR(64) ACTION_CD NUMBER(1) USER_ID CHAR(50) NOTE VARCHAR2(200) SQL> select INDEX_NAME,TABLE_NAME,COLUMN_NAME,COLUMN_POSITION 2 from user_ind_columns where table_name = 'LOGTBL1'; INDEX_NAME TABLE_NAME COLUMN_NAME COLUMN_POSITION ------------ ------------ ------------ --------------- IDX_LOGTBL1 LOGTBL1 NODE_NO 1 IDX_LOGTBL1 LOGTBL1 INS_DATE 2
<>
もうひとつの案は、「インスタンス内での競合を抑えよう。」です。
これは、RACに限らず使える方法です。ずばり、リバースインデックスです。
昇順にインサートされるデータも、末尾の値は必ずしも昇順ではありません。
これを利用することで、インサート時の同一ブロックの競合を避けることが
出来ます。
さて、今回は、どちらを採用することにしましょうか。どちらを採用するに
しても、それほどアプリケーション側の変更には、影響がない様におもわれ
ます。皆さんはどちらを選ぶでしょうか。
大きなポイントは、”インデックスの目的”です。
今、データのインサート時におけるブロックの競合に着目していますが、も
ともとインデックスは検索時の効率化を計るための機能なので、これを最低
限満たしていないと、そもそも負荷をかけてインデックスを作る必要がなく
なります。
そこで、今回の対象となっている、ログ系のインデックスの目的を確認して
みます。
先にもあげましたが、
・いつ、どれくらいの新規登録が行われたか
・いつ、どれくらいの更新が行われたか
・どの時間帯に誰が処理しているか
などのように、時間帯での分析・集計が用途となります。
つまり、”レンジスキャン”です。
もうわかりますね。リバースインデックスは使えません。
どう転んでも、時刻データがばらばらにインデックスリーフブロックに収ま
るために、範囲検索が出来なくなるのです。
正確には、アプリケーションとして動くけれども「その負荷は察して恐るべ
し。」
というわけで、今回は、node_noというインスタンスを特定するカラムを追加
することで対応することにしました。これで、インスタンス間をまたがった
インサート時の同一ブロック競合は防げるはずです。
では早速レスポンスをみてみましょう。、、、、んん?
おっと、まったまった。うっかりして大事なことを忘れていました。
インデックスのカラムを変更したので、あわせて検索するアプリケーション
を変更する必要があるはずです。さて、どうしましょうか。まずはこのまま
検索して現状の実行計画を見てみましょう。
(node_noを追加したテーブル・インデックスで検索)
SQL> select * from logtbl1 2 where ins_date > sysdate -1 and ins_date <= sysdate; 6666行が選択されました。 実行計画 ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (FULL) OF 'LOGTBL1' 統計 ---------------------------------------------------------- 0 recursive calls 0 db block gets 4524 consistent gets 0 physical reads 0 redo size 926564 bytes sent via SQL*Net to client 5387 bytes received via SQL*Net from client 446 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 6666 rows processed
インデックスが使われていませんね。ちなみに、以下がこれまでのテーブル
・インデックスでの実行計画です。インデックスが使用されており、
consistent getsを比べると、その差は4倍以上です。
(従来のテーブル・インデックスで検索)
実行計画 ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'LOGTBL1' 2 1 INDEX (RANGE SCAN) OF 'IDX_LOGTBL1' (NON-UNIQUE) 統計 ---------------------------------------------------------- 0 recursive calls 0 db block gets 1007 consistent gets 0 physical reads
で、どうするかと言うと、やはりインデックスを使ってもらうようにしない
といけません。アプリケーションとしてはヒント句を追加する方法が手っ取
り早いでしょう。
ためしに以下のようにしてみました。(検証環境の結果です。)
SQL> select /*+ index(logtbl1 idx_logtbl1) */ * 2 from logtbl1 3 where ins_date > sysdate -1 and ins_date <= sysdate; 6666行が選択されました。 実行計画 ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=29 Card=832 Bytes=215488) 1 0 FILTER 2 1 TABLE ACCESS (BY INDEX ROWID) OF 'LOGTBL1' (Cost=29 Card=832 Bytes=215488) 3 2 INDEX (FULL SCAN) OF 'IDX_LOGTBL1' (NON-UNIQUE) (Cost=26 Card=832) 統計 ---------------------------------------------------------- 0 recursive calls 0 db block gets 1624 consistent gets 0 physical reads 0 redo size 926564 bytes sent via SQL*Net to client 5387 bytes received via SQL*Net from client 446 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 6666 rows processed
consistent getsがかなり減りました。効果絶大ですね。
でも、皆さん何か気になりませんか。よーくみてください。
実行計画のところで、インデックスのFULL SCANが実行されています。つまり、
「複合インデックスで先頭カラムに条件以外のカラムがある場合、インデッ
クスの中をすべて見ないとデータの存在がわからない。」と言うことになって
いるんですね。
ただし、結果として、FULL SCANするよりも負荷は下がっているようなので、
この検証環境においては効果はあったようです。ただし、いつでも有効かど
うかは疑問ですね。
続きはまた来週。
梅雨の晴れ間に布団干し 茅ヶ崎にて