Oracle インメモリ設定のパフォーマンス向上効果

 2015.10.01  株式会社システムインテグレータ

Oracle Database 12cで注目されている
「Oracle Database In-Memory」

この度「SI Object Browser for Oracle Ver.13.0」(以下、Object Browser)がこの機能に対応しましたので今回のDBラボはインメモリについて行っていこうと思います。

インメモリとは?

Oracle Database 12cの代表的な機能の一つであり、「Oracle Database In-Memory」といいます。
メモリー上にカラムフォーマットで載せることにより、分析系クエリが高速化し、従来のローフォーマットも同時に使用することでトランザクション処理のパフォーマンスも向上するのが特徴です。
導入の際にアプリケーション側での変更は必要なく、テーブル定義の変更でインメモリ化が可能となっています。
(※この機能はOracle 12c(12.1.0.2)からご利用できます。)

従来の通常テーブルとインメモリ設定を施したインメモリテーブルでどの程度パフォーマンスが向上するか、今回は以下のケースについて検証しようと思います。

ケース1:テーブルの全件検索
ケース2:テーブルの1レコード検索とインデックス検索
ケース3:表結合でも有効か否か

 

検証環境

今回の検証環境は以下の通りです。

クライアント環境

OS Windows Server 2012 R2 Standard (64ビット)
CPU Intel(R) Xeon(R)CPU E5-2670 v2 @2.50GHz
メモリ 7.50GB
補足1 SI Object Browser Ver.13 をインストール

サーバー環境

補足1 クライアントと同じ環境

データベース

製品名 Oracle Database 12c
エディション Enterprise Edition
バージョン 12.1.0.2.0
ビット数 64ビット
補足1 SGAのサイズを十分に確保すること(当環境は3GB確保しています)
補足2 初期化パラメータ "inmemory_size" を 500MB 以上にすること

 

ケース1:テーブルの全件検索

従来の通常テーブルとインメモリ設定を施したインメモリテーブルでフルスキャンを行った際にどのくらいの違いが生じるのだろうか?
従来のテーブルとインメモリ化したテーブルを比較し、平均実行時間を調べました。

ケース1の準備

まず、ベースになるテーブルを下記SQLで作成します。

CREATE TABLE TBL_LABO_NOMAL
(
F_ID        NUMBER NOT NULL,
F_VALUE     NUMBER,
F_DATE      DATE,
CONSTRAINT PK_TBL_LABO_NOMAL PRIMARY KEY (F_ID) USING INDEX
)
/

上記のテーブルを作成した後、データの作成を行います。
今回は500万レコードセットした状態で行います。もちろん手入力では作成が難しいので、
SI Object Browserのデータ生成ツールの機能を使用します。
詳細は(第1回参照)

F_ID 列の設定値:無難に1~の連番を設定しました。

disp_201510_1_img_1_データ生成ツール.png

F_VALUE 列の設定値:全て整数になるように丸め値を設定しました。

disp_201510_1_img_2_データ生成ツール.png

F_DATE 列の設定値:日付の乱数値を設定しました。

disp_201510_1_img_3_データ生成ツール.png

データの作成が終了しましたら、次はインメモリテーブルを作成します。
SI Object Browserのオブジェクトリストより「TBL_LABO_NOMAL」を選択し、右クリックよりコピー&ペーストを行います。リネームを促されますので下記画像のように変更します。

disp_201510_1_img_4_テーブルコピー.pngコピーが終わったら、次はインメモリの設定を行います。
テーブル画面より[IM列ストア]タブの左上のチェックボックスをチェックし、圧縮方法を「FOR QUERY LOW」を指定して[作成]ボタンを押すことでインメモリ設定を行います。
また、事前に右上の見積機能を使い、メモリがどの程度使用されるかを確認しておくことをお勧めします。

データベース開発に関するお役立ち資料

disp_201510_1_img_5_IME列ストア.png

インメモリ領域の空き領域を確認しておきます。3004MBの空きがあるので実験には問題ありません。

disp_201510_1_img_6_インメモリ情報.png

 

ケース1の実験開始

準備が整いましたら、下記SQLで実行時間を計測していきます。

※平均実行時間について
10回計測を行い、そのうちの5つの中央値を使用。その5つの値の平均を平均実行時間とします。

SELECT
COUNT(F_VALUE), MAX(F_VALUE), MIN(F_VALUE), AVG(F_VALUE)
FROM
テーブル名
/

 
通常テーブル(TBL_LABO_NOMAL)

 

  計算対象 実行時間(秒)
1回目 1 2.532
2回目 9 1.985
3回目 6 2.031
4回目 7 2.000
5回目 2 2.515
6回目 10 1.984
7回目 4 2.328
8回目 5 2.219
9回目 3 2.453
10回目 7 2.000
平均実行時間 2.206
インメモリテーブル(TBL_LABO_IM)

 

  計算対象 実行時間(秒)
1回目 1 2.532
2回目 3 0.641
3回目 6 0.625
4回目 6 0.625
5回目 6 0.625
6回目 6 0.625
7回目 2 0.657
8回目 4 0.640
9回目 4 0.640
10回目 6 0.625
平均実行時間 0.625

 

disp_201510_1_img_7_ケース1グラフ.png

テスト1考察

圧倒的にインメモリの方が早いという結果となりました。
フルスキャンに関してはインメモリの方が圧倒的に早くなっています。

ケース2:テーブルの1レコード検索とインデックス検索

次は通常テーブル、インデックス有りの通常テーブル、そしてインメモリテーブルの実行時間を計測します。

ケース2の準備

下記のテスト1と同様の方法で新しいテーブル(TBL_LABO_NOMAL2)を作成します。
作成後に下記SQLでインデックスを付加します。

CREATE INDEX IX_TBL_LABO_NOMAL2
ON TBL_LABO_NOMAL2(F_DATE)
/

作成したら次はテスト1と同様の方法でTBL_LABO_NOMAL2 に TBL_LABO_NOMAL のデータをコピーします。

ケース2の実験開始


準備が整いましたら、下記SQLで実行時間を計測していきます。

SELECT
COUNT(F_VALUE), MAX(F_VALUE), MIN(F_VALUE), AVG(F_VALUE)
FROM
TBL_LABO_NOMAL2
WHERE
F_DATE = TO_DATE('1レコードに絞り込む日時', 'YYYY/MM/DD HH24:MI:SS')
/

通常テーブル(TBL_LABO_NOMAL)

 

  計算対象 実行時間(秒)
1回目 1 2.922
2回目 3 2.468
3回目 6 2.172
4回目 2 2.609
5回目 7 2.125
6回目 4 2.453
7回目 9 2.016
8回目 5 2.187
9回目 10 1.953
10回目 8 2.078
平均実行時間 2.203
通常テーブル・INDEX付与(TBL_LABO_NOMAL2)

 

  計算対象 実行時間(秒)
1回目 1 0.500
2回目 2 0.110
3回目 4 0.094
4回目 10 0.078
5回目 4 0.094
6回目 3 0.109
7回目 4 0.094
8回目 4 0.094
9回目 9 0.093
10回目 4 0.094
平均実行時間 0.094
インメモリテーブル(TBL_LABO_IM)

 

  計算対象 実行時間(秒)
1回目 1 0.766
2回目 3 0.157
3回目 8 0.125
4回目 5 0.141
5回目 6 0.140
6回目 4 0.156
7回目 2 0.172
8回目 8 0.125
9回目 6 0.140
10回目 8 0.125
平均実行時間 0.140

 

disp_201510_1_img_8_ケース2グラフ.png

テスト2考察

平均実行時間は若干ですがインデックス有りの通常テーブルが早いという結果になりました。
これはインメモリが大量レコードの中から数行のレコードを取得するのが、あまり得意でないという点も影響していると思いますが、インデックス無しの通常テーブルと比較した場合、パフォーマンスは大きく向上しており、インメモリ化してインデックスを外しても大きくパフォーマンス低下することはなさそうです。

※Oracle公式ホームページでは導入前の事前調査と、メモリー管理が重要であると明言されています。実装の際は実行計画を有効に活用し、チューニングを行ったほうが良いと思います。 [RELATED_POSTS]

ケース3:表結合でも有効か否か

普段の開発で使用しているような結合(JOIN)しているテーブルにも有効だろうか?
従来のテーブルをLEFT JOINしたものとインメモリテーブルをLEFT JOINしたものを比較し、平均実行時間を調べました。

ケース3の準備

1つのトランザクションテーブルに3つのマスタテーブルが結合したものを計測するため、下記の8つのテーブルを用意します。また、レコード数はトランザクションテーブルに500万件、マスタテーブルには10万件の登録して計測します。

■通常テーブル ■インメモリテーブル
TBL_LABO_TRN TBL_LABO_TRN_IM
  TBL_LABO_MST1   TBL_LABO_MST1_IM
  TBL_LABO_MST2   TBL_LABO_MST2_IM
  TBL_LABO_MST3   TBL_LABO_MST3_IM

トランザクションテーブルの内容は以下のようになっております。

CREATE TABLE RA_DBA.TBL_LABO_TRN
(
F_ID        NUMBERNOTNULL,
F_NAME      VARCHAR2(64),
F_DATE      DATE,
F_MST1_ID   NUMBER,--TBL_LABO_MST1のキー
F_MST2_ID   NUMBER,--TBL_LABO_MST2のキー
F_MST3_ID   NUMBER,--TBL_LABO_MST3のキー
F_TEXT      VARCHAR2(256),
CONSTRAINT PK_TBL_LABO_TRN PRIMARY KEY (F_ID) USING INDEX
)
/

※TBL_LABO_TRN_IM も同じ構成のため割愛します。

マスタテーブルの内容は以下のようになっております。

CREATE TABLE RA_DBA.TBL_LABO_MST1
(
F_MST1_ID   NUMBER NOT NULL,
F_VALUE     NUMBER,
F_DATE      DATE,
F_TEXT      VARCHAR2(256),
CONSTRAINT PK_TBL_LABO_MST1_IM PRIMARY KEY (F_MST1_ID) USING INDEX
)
/

 

※TBL_LABO_MST2 / TBL_LABO_MST3 / TBL_LABO_MST1_IM / TBL_LABO_MST2_IM / TBL_LABO_MST3_IM も同じ構成のため割愛します。

 

作成したら次はテスト1と同様の方法でトランザクションテーブルをコピーで作成、マスタテーブルを7つコピーします。
データが全て作成し終えた状態で「_IM」が末尾に付いたテーブルをインメモリ化します。

ケース3の実験開始

準備が整いましたら、下記SQLで実行時間を計測していきます。

SELECT

COUNT(A.F_ID)
, MAX(A.F_DATE), MAX(B.F_VALUE), MAX(C.F_VALUE), MAX(D.F_VALUE)
FROM
トランザクションテーブル
LEFT JOIN
マスタテーブル1 B
ON A.F_MST1_ID = B.F_MST1_ID
LEFT JOIN
マスタテーブル2 C
ON A.F_MST2_ID = C.F_MST2_ID
LEFT JOIN
マスタテーブル3 D
ON A.F_MST3_ID = D.F_MST3_ID
/

 
全て通常テーブル

 

  計算対象 実行時間(秒)
1回目 2 19.781
2回目 6 17.922
3回目 4 18.625
4回目 9 16.844
5回目 5 18.453
6回目 3 19.281
7回目 1 21.422
8回目 7 17.516
9回目 8 17.000
10回目 10 16.266
平均実行時間 18.359
マスタのみインメモリ

 

  計算対象 実行時間(秒)
1回目 2 19.734
2回目 10 15.375
3回目 6 17.157
4回目 8 15.453
5回目 5 17.500
6回目 9 15.422
7回目 7 16.734
8回目 4 18.032
9回目 1 21.610
10回目 3 18.797
平均実行時間 17.644

 

トランザクションテーブルのみインメモリ

 

  計算対象 実行時間(秒)
1回目 1 5.625
2回目 2 5.094
3回目 9 4.609
4回目 10 4.547
5回目 3 5.032
6回目 4 4.953
7回目 6 4.938
8回目 8 4.672
9回目 4 4.953
10回目 7 4.922
平均実行時間 4.960
全てインメモリ

 

  計算対象 実行時間(秒)
1回目 1 7.046
2回目 10 3.968
3回目 5 4.157
4回目 9 3.969
5回目 3 4.265
6回目 2 4.469
7回目 4 4.235
8回目 7 4.015
9回目 6 4.141
10回目 8 4.000
平均実行時間 4.163

 

パターン 平均実行時間
全て通常テーブル 18.359
マスタのみインメモリ 17.644
トランザクションテーブルのみインメモリ 4.960
全てインメモリ 4.163

 

disp_201510_1_img_9_ケース3グラフ.png

テスト3考察

インメモリ化を行うことでパフォーマンスはいずれも向上しました。
そしてインメモリにしている割合に応じてパフォーマンスも向上しました。

※「トランザクションのみ」が早いのは単純にマスタに対してデータ量の割合が大きくインメモリの恩恵もより大きく受けているからだと推測します。

結論

今回の検証結果では、以下のようになりました。
・インメモリ化はパフォーマンス向上に役立つ
・インデックスと同等の性能を持っている
・データ量が多ければ多いほど恩恵が大きい

今回の検証は本当に単純なテーブルの比較でしたが、インメモリはインデックスを使用してない列への検索は圧倒的に早いという結果になりました。
テスト2では僅差でインデックスの検索スピードに負けましたが、インデックスは断片化によるパフォーマンス低下や更新時のオーバーヘッドを持ち合わしているためインメモリ化はこれらを解消するというチューニングとしても期待できます。

しかし、何も考えずにインメモリ化を行えば、インメモリ領域がすぐに枯渇するのは明らかです。
そのため、インメモリ化は実装する前に事前にパフォーマンスが上がるか否かを検証し、ボトルネックになるテーブル、もしくは更新頻度は高いが多数のインデックスが存在するテーブルにのみインメモリ設定を行なう等の方針決めなどの必要性を感じました。

新規CTA

RECENT POST「DBlab」の最新記事


この記事が気に入ったらいいねしよう!
OBトライアル
ブログ購読のお申込み

RANKING人気資料ランキング

RANKING人気記事ランキング

RECENT POST 最新記事