8 インメモリー結合の最適化
Database In-Memoryは、インメモリー結合のパフォーマンスを向上する複数の機能をサポートしています。
インメモリー結合について
結合は、データ・ウェアハウジング・ワークロードの不可欠な一部です。結合される表がメモリーに格納されている場合、IM列ストアにより、結合のパフォーマンスが向上します。
スキャンおよび結合処理が高速化されるため、ブルーム・フィルタを使用する複雑な複数表結合および単純な結合には、IM列ストアが役立ちます。データ・ウェアハウジング環境では、最も頻繁に使用される結合には、1つのファクト表と1つ以上のディメンション表が関与しています。
次の結合は、表がIM列ストアに移入される場合に、より高速に実行されます。
-
ブルーム・フィルタを使用できる結合
-
複数の小規模なディメンション表の、1つのファクト表への結合
-
主キーと外部キーの関係がある2つの表の間の結合
結合グループによる結合の最適化
インメモリー結合は、CREATE INMEMORY JOIN GROUP
文を使用して結合グループを作成することで最適化できます。
ヒント:
自動インメモリー管理AIMがワークロードを自動的に分析して、結合グループが有益な可能性がある場所を判断できるようになりました。次に、結合グループを作成し、そのパフォーマンスへの影響を監視し、改善がない場合に変更を元に戻します。AIMはデフォルトで有効です。結合グループについて
結合グループは、頻繁に結合される1〜255列のグループです。
結合グループの表セットには、1つ以上の内部表が含まれています。外部表はサポートされていません。IM列ストアが有効化されていると、データベースでは移入された表の結合を最適化するために結合グループを使用できるようになります。
結合グループ内の列は、同じ表内または異なる表内にある可能性があります。たとえば、sales
とtimes
がtime_id
列で頻繁に結合される場合は、(times(time_id), sales(time_id))
の結合グループを作成できます。employees
表が、それ自体のemployee_id
列に結合されることが多い場合は、結合グループ(employees(employee_id))
を作成します。
ノート:
同じ列が複数の結合グループのメンバーになることはできません。
結合グループを作成すると、データベースにより、その結合グループで参照されている表の現在のインメモリー・コンテンツが無効になります。後続の再移入により、データベースで、共通ディクショナリによる表のIMCUの再エンコードが引き起こされます。このため、最初に結合グループを作成し、その後、表に移入することをお薦めします。
CREATE INMEMORY JOIN GROUP
文を使用して結合グループを作成します。結合グループに列を追加するか、結合グループから列を削除するには、ALTER INMEMORY JOIN GROUP
文を使用します。DROP INMEMORY JOIN GROUP
文を使用して結合グループを削除します。
ノート:
Oracle Active Data Guardでは、スタンバイ・データベースで結合グループ定義が無視されます。スタンバイ・データベースでは、共通ディクショナリは使用されず、結合グループが存在しないかのように問合せが実行されます。
例8-1 結合グループの作成
この例では、hr.employees
表内およびhr.departments
表内のdepartment_id
を含む、deptid_jg
という名前の結合グループを作成します。
CREATE INMEMORY JOIN GROUP deptid_jg (hr.employees(department_id),hr.departments(department_id));
結合グループの目的
特定の問合せでは、結合グループにより、列値の解凍およびハッシュについてパフォーマンスのオーバーヘッドがなくなります。
結合グループを使用しないときは、オプティマイザでハッシュ結合を使用するがブルーム・フィルタを使用できないか、ブルーム・フィルタで行が効率的にフィルタされない場合に、データベースで、IMCUを解凍し、コストのかかるハッシュ結合を使用する必要があります。問題を示すため、スター・スキーマにsales
ファクト表およびvehicles
ディメンション表があると仮定します。次の問合せでは、これらの表が結合されますが、出力はフィルタされません。これは、データベースでブルーム・フィルタを使用できないことを意味します。
SELECT v.year, v.name, s.sales_price
FROM vehicles v, sales s
WHERE v.name = s.name;
次の図に、データベースによる2つのデータ・セットの結合方法を示します。
データベースは、次のようにハッシュ結合を実行します。
-
vehicles
表をスキャンし、述語を満たす行(このケースでは、フィルタが存在しないため、すべての行が述語を満たします)を解凍し、行をハッシュ結合に送信します。 -
解凍した行に基づいてPGAでハッシュ表を作成します
-
sales
表をスキャンし、フィルタを適用します(この場合、問合せはフィルタを指定しません) -
IMCUから一致する行を処理して、その行を結合に送信します
調査側(この例では、
sales
表)の行セットがハッシュ結合で利用できる場合は、表スキャンによって送信される行セットは圧縮された形式になります。構築側から一致する行を検索するためにローカル・ディクショナリまたは結合グループが利用されるかどうかに応じて、ハッシュ結合で行が解凍されるか、未圧縮のままにされます。 -
結合列(この場合、乗物名)を使用してハッシュ表を調べます
結合グループがv.name
列およびs.name
列に存在する場合、データベースは前述のステップをより効率的に実行します(解凍とフィルタリングのオーバーヘッドがなくなります)。結合グループの利点は次のとおりです。
-
データベースは、圧縮されたデータに対して機能します。
-
データベースは、調査行とハッシュされた行の結合キーの比較が必要になる結合キーのハッシングとハッシュ表の調査を回避します。
結合グループが存在する場合、データベースは結合列値ごとのコードを共通ディクショナリに格納します。データベースは、ディクショナリのコードを使用して結合グループの配列を作成します。すべての配列要素は、ハッシュ領域(通常は、PGAメモリー)に格納されている構築側の行をポイントしています。調査時に、各調査行は結合キーに関連付けられたコードを保持しています。データベースは、このコードを使用して配列を検索し、配列要素にポインタが存在しているかどうかを調べます。ポインタが存在する場合は一致があり、それ以外の場合は一致がありません。
-
ディクショナリ・コードは稠密および固定長であるため、領域が効率的に使用されます。
-
結合グループによる問合せの最適化は、ブルーム・フィルタを使用できないときに可能な場合があります。
結合グループの仕組み
結合グループでは、データベースによって、同じ共通ディクショナリを使用して結合グループ内のすべての列が圧縮されます。
結合グループでどのように共通ディクショナリが使用されるか
共通ディクショナリは、表レベルのディクショナリ・コードのセットです。
共通ディクショナリは、単一インスタンスのOracleデータベースおよびOracle RAC One Nodeデータベースにおいてインスタンス固有です。Oracle RACクラスタでは、クラスタのすべてのノードに分散したグローバル・ディクショナリです。
データベースでは、基になる列で結合グループが定義されている場合に、IM列ストア内に共通ディクショナリが自動的に作成されます。共通ディクショナリにより、複数の結合列で同じディクショナリ・コードを共有できるようになります。
共通ディクショナリには、次のような利点があります。
-
共通ディクショナリからのコードでローカル・ディクショナリ内の値をエンコードします。それにより、圧縮が提供され、IMCUのキャッシュ効率が向上します
-
結合でディクショナリ・コードを使用して、ハッシュ結合中に使用されるデータ構造を構成および調査できます
-
オプティマイザにより、カーディナリティ、列値の分布などの統計を取得できます
次の図は、sales.name
列とvehicles.name
列で作成された結合グループに対応する、共通ディクショナリを示しています。
データベースで共通ディクショナリが使用される場合、各CUのローカル・ディクショナリには、元の値(AUDI
、BMW
、CADILLAC
、FORD
など)は格納されません。かわりに、ローカル・ディクショナリには、共通ディクショナリに格納されている値への参照が格納されます。たとえば、ローカル・ディクショナリではAudi
に値101
、BMW
には220
を格納できます。共通ディクショナリでは、Audi
に0
、BMW
に1
を格納できます。ローカル・ディクショナリの101
(AUDI)は、共通ディクショナリの0
(AUDI)へのポインタです。
結合グループでどのようにスキャンが最適化されるか
主要な最適化は、列値ではなく共通ディクショナリ・コードでの結合であり、それによって、結合にハッシュ表を使用しないようにします。
結合グループを使用してvehicles
とsales
をname
列で結合する、次のような問合せについて考察します。
SELECT v.year, v.name, s.sales_price
FROM vehicles v, sales s
WHERE v.name = s.name
AND v.name IN ('Audi', 'BMW', 'Porsche', 'VW');
次の図では、結合グループで作成された共通ディクショナリがどのように結合に役立つかを示します。
前述の図に示されているように、データベースは次のように圧縮されたデータのハッシュ結合を実行します。
-
vehicles
表をスキャンし、0
(Audi)、1
(BMW)、2
(Cadillac)などのディクショナリ・コード(元の列値ではない)をハッシュ結合に送信します。 -
PGA内で非重複共通ディクショナリ・コードの配列を構築します。
-
sales
表をスキャンし、フィルタを適用します(このケースでは、ドイツ車のみのフィルタとなります) -
一致する行を、圧縮された形式で結合に送信します。
-
ハッシュ表のプロービングではなく、配列内の対応する値を探します。それにより、結合キー列上のハッシュ関数を計算する必要がなくなります。
この例では、vehicles
表には7行のみがあります。vehicles.name
列には、次のような値があります。
Audi
BMW
Cadillac
Ford
Porsche
Tesla
VW
共通ディクショナリにより、ディクショナリ・コードが各非重複値に割り当てられます。概念的には、共通ディクショナリは、次のようになります。
Audi 0
BMW 1
Cadillac 2
Ford 3
Porsche 4
Tesla 5
VW 6
データベースで、vehicles.name
がスキャンされます。最初のIMCU内の最初のディクショナリ・コードから始まり、最後のIMCU内の最後のコードで終わります。フィルタ(ドイツ車のみ)に適合するすべての行については1
、フィルタに適合しないすべての行については0
が格納されます。概念上、配列は次のようになります。
array[0]: 1
array[1]: 1
array[2]: 0
array[3]: 0
array[4]: 1
array[5]: 0
array[6]: 1
データベースでは、次に、sales
ファクト表がスキャンされます。この例を単純化するために、sales
表には6行のみがあると仮定します。データベースでは、次のように行がスキャンされます(値ごとの共通ディクショナリ・コードを括弧で囲んで示します)。
Cadillac (2)
Cadillac (2)
BMW (1)
Ford (3)
Audi (0)
Tesla (5)
データベースでは、次に、vehicles.name
配列内を進み、一致を探します。行が一致すると、データベースにより、一致する行がその関連する共通ディクショナリ・コードとともに送信され、対応する列値がvehicles.name
およびsales.name
IMCUから取得されます。
2 -> array[2] is 0, so no join
2 -> array[2] is 0, so no join
1 -> array[1] is 1, so join
3 -> array[3] is 0, so no join
0 -> array[0] is 1, so join
5 -> array[5] is 0, so no join
ハッシュ結合で共通ディクショナリ・エンコーディングが使用される場合
通常、結合グループ内の列を結合することでパフォーマンスが向上します。
結合グループの作成時に、次の処理がデータベースによって実行されます。
-
結合キー列に対応するディクショナリ値のハッシュがキャッシュされます
-
結合キー列に対応する
NUMBER
データのバイナリ表現がキャッシュされます -
同じ共通ディクショナリで列がエンコードされます
結合グループ内の列の結合では、最初の2つの最適化が常に使用されるためパフォーマンスが向上します。たとえば、オプティマイザがハッシュ結合を選択すると、問合せはブルーム・フィルタの調査にハッシュ値を使用するようになります。問合せでIM集計結合が使用される場合、問合せはキー・ベクターへの索引付けにキャッシュされた2進数を使用します。
ハッシュ結合には、ディクショナリ・エンコーディングが使用されることも使用されないこともあります。ハッシュ結合の少なくとも1つの列にディクショナリ・エンコーディングが存在する場合、問合せでは次の方法でエンコーディングを活用できます。
-
結合グループ対応のハッシュ結合
実行時に、ハッシュ結合の両方の列が共通ディクショナリ・エンコーディング・データを保持します。実行計画は、ハッシュ結合の両側が関与する分散のないパラレル・ハッシュ結合計画か、シリアル・ハッシュ結合計画のどちらかを必ず示します。
-
エンコーディング対応のハッシュ結合
実行時に、ハッシュ結合内の1つのファクト表列がディクショナリ・エンコーディング・データを保持します。実行計画は、ハッシュ結合の右側からの分散のないパラレル・ハッシュ結合か、シリアル・ハッシュ結合計画のどちらかを必ず示します。共通ディクショナリの圧縮率が良好な場合や、パラレル・ハッシュ結合計画では結合グループ対応のハッシュ結合を活用できない場合(並列ブロードキャストなしの計画など)、問合せでは共通ディクショナリにエンコーディング対応ハッシュ結合を使用することもできます。
SQL監視レポートでは、ディクショナリの使用がColumnar Encodings Observed
フィールドとColumnar Encodings Leveraged
フィールドで示されます。この統計は累積されます。パラレル・ハッシュ結合の場合、このフィールドには、行ソースの実行に関連するすべての子プロセスから収集した統計が集約されます。IMCU内のローカル・ディクショナリの観点では、この統計には、右側の子行ソースで観測されたエンコーディングIDの数と、結合で利用されたエンコーディングの数が示されます。単一プロセスのハッシュ結合が共通ディクショナリを利用する場合、Columnar Encodings Leveraged
には、結合で利用されたエンコーディングの数が示されます。
次の表に、Columnar Encodings Observed
とColumnar Encodings Leveraged
に示される可能性のある値と、その組合せが意味する内容を示します。
表8-1 SQL監視レポートでの結合グループの使用
観測された列形式エンコーディング | 利用された列形式エンコーディング | エンコーディング対応ハッシュ結合の使用 | 結合グループ対応ハッシュ結合の使用 |
---|---|---|---|
存在しない |
存在しない |
なし |
なし |
正の値 |
存在しない |
なし |
なし |
正の値 |
正の値 |
あり |
なし |
存在しない |
正の値 |
なし |
はい |
たとえば、Columnar Encodings Leveraged
フィールドに4
が示されていているときに(並列度が4であると仮定)、Columnar Encodings Observed
フィールドが存在していない場合、問合せはハッシュ結合に結合グループを利用したことを意味します。Columnar Encodings Observed
フィールドが4
のときに、Columnar Encodings Leveraged
フィールドが存在しない場合、ディクショナリ・エンコーディングが存在していても、問合せでは使用されなかったことを意味します。
様々な要因によって、問合せでエンコーディング対応ハッシュ結合が使用されなくなることがあります。こうした要因には次のものがあります。
-
共通ディクショナリの圧縮率が最適でない。
-
共通ディクショナリなしで表スキャンから渡された行セットが多すぎることが問合せで観測された。
-
構築側の行の長さが長すぎる。
-
構築側の行がPGAメモリーに収まりきらない。
-
構築側に重複した結合キーがある。
関連項目:
結合グループの作成
CREATE INMEMORY JOIN GROUP
文を使用して結合グループを定義します。
結合グループの候補は、結合述語で頻繁にペアにされる列です。代表的な例に、ファクト表とディメンション表を結合する列、または表をそれ自体に結合する列などがあります。
CREATE INMEMORY JOIN GROUP
文は、結合グループをただちに定義します。これは、そのメタデータがデータ・ディクショナリに表示されることを意味します。データベースでは、共通ディクショナリはすぐには構成されません。正確に述べると、データベースでは、次回、結合グループ内で参照されている表が、IM列ストアに移入されるか再移入されるときに共通ディクショナリが構築されます。
ガイドライン
結合グループを作成、変更または削除すると、通常は、その結合グループ内で参照されている、基にあるすべての表が無効になります。そのため、表を最初に移入する前に結合グループを作成することをお薦めします。
結合グループを作成するには:
-
SQL*PlusまたはSQL Developerで、必要な権限を持つユーザーとしてデータベースにログインします。
-
次の形式の文を使用して、結合グループを作成します。
CREATE INMEMORY JOIN GROUP join_group_name ( table1(col1), table2(col2) );
たとえば、次の文は、
sales_products_jg
という結合グループを作成します。CREATE INMEMORY JOIN GROUP sales_products_jg (sales(prod_id), products(prod_id));
-
オプションで、データ・ディクショナリを問い合せて、結合グループの定義を表示します(出力例も示します)。
COL JOINGROUP_NAME FORMAT a18 COL TABLE_NAME FORMAT a8 COL COLUMN_NAME FORMAT a7 SELECT JOINGROUP_NAME, TABLE_NAME, COLUMN_NAME, GD_ADDRESS FROM DBA_JOINGROUPS; JOINGROUP_NAME TABLE_NA COLUMN_ GD_ADDRESS ------------------ -------- ------- ---------------- SALES_PRODUCTS_JG SALES PROD_ID 00000000A142AE50 SALES_PRODUCTS_JG PRODUCTS PROD_ID 00000000A142AE50
-
結合グループ内で参照されている表を移入します。または、現在移入されている場合は、それらを再移入します。
例8-2 結合グループの使用による問合せの最適化
この例では、データベースにSYSTEM
としてログインしてから、まだIM列ストアに移入されていないsales
およびproducts
のprod_id
列で結合グループを作成します。
CREATE INMEMORY JOIN GROUP
sh.sales_products_jg (sh.sales(prod_id), sh.products(prod_id));
IM列ストアへの移入のためにsh.sales
表およびsh.products
表を有効にします。
ALTER TABLE sh.sales INMEMORY;
ALTER TABLE sh.products INMEMORY;
次の問合せでは、それらの表がまだIM列ストアに移入されていないことが示されます(出力例が含まれています)。
COL OWNER FORMAT a3
COL NAME FORMAT a10
COL STATUS FORMAT a20
SELECT OWNER, SEGMENT_NAME NAME,
POPULATE_STATUS STATUS
FROM V$IM_SEGMENTS;
no rows selected
両方の表を問い合せて、それらをIM列ストアに移入します。
SELECT /*+ FULL(s) NO_PARALLEL(s) */ COUNT(*) FROM sh.sales s;
SELECT /*+ FULL(p) NO_PARALLEL(p) */ COUNT(*) FROM sh.products p;
次の問合せでは、それらの表が現在はIM列ストアに移入されていることが示されます(出力例が含まれています)。
COL OWNER FORMAT a3
COL NAME FORMAT a10
COL PARTITION FORMAT a13
COL STATUS FORMAT a20
SELECT OWNER, SEGMENT_NAME NAME, PARTITION_NAME PARTITION,
POPULATE_STATUS STATUS, BYTES_NOT_POPULATED
FROM V$IM_SEGMENTS;
OWN NAME PARTITION STATUS BYTES_NOT_POPULATED
--- ---------- ------------- -------------------- -------------------
SH SALES SALES_Q3_1998 COMPLETED 0
SH SALES SALES_Q4_2001 COMPLETED 0
SH SALES SALES_Q4_1999 COMPLETED 0
SH PRODUCTS COMPLETED 0
SH SALES SALES_Q1_2001 COMPLETED 0
SH SALES SALES_Q1_1999 COMPLETED 0
SH SALES SALES_Q2_2000 COMPLETED 0
SH SALES SALES_Q2_1998 COMPLETED 0
SH SALES SALES_Q3_2001 COMPLETED 0
SH SALES SALES_Q3_1999 COMPLETED 0
SH SALES SALES_Q4_2000 COMPLETED 0
SH SALES SALES_Q4_1998 COMPLETED 0
SH SALES SALES_Q1_2000 COMPLETED 0
SH SALES SALES_Q1_1998 COMPLETED 0
SH SALES SALES_Q2_2001 COMPLETED 0
SH SALES SALES_Q2_1999 COMPLETED 0
SH SALES SALES_Q3_2000 COMPLETED 0
DBA_JOINGROUPS
を問い合せ、結合グループに関する情報を取得します(出力例が含まれています)。
COL JOINGROUP_NAME FORMAT a18
COL TABLE_NAME FORMAT a8
COL COLUMN_NAME FORMAT a7
SELECT JOINGROUP_NAME, TABLE_NAME, COLUMN_NAME, GD_ADDRESS
FROM DBA_JOINGROUPS;
JOINGROUP_NAME TABLE_NA COLUMN_ GD_ADDRESS
------------------ -------- ------- ----------------
SALES_PRODUCTS_JG SALES PROD_ID 00000000A142AE50
SALES_PRODUCTS_JG PRODUCTS PROD_ID 00000000A142AE50
上の出力では、結合グループsales_products_jg
が同じ共通ディクショナリ・アドレスで結合されていることが示されています。
関連項目:
-
CREATE INMEMORY JOIN GROUP
文について学習するには、『Oracle Database SQL言語リファレンス』を参照してください -
DBA_JOINGROUPS
ビューについて学習するには、『Oracle Databaseリファレンス』を参照
結合グループの使用の監視
問合せで結合グループが使用されているかどうかを判断するには、グラフィカルなSQL監視レポート(推奨)を使用することも、DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML
ファンクションを使用するSQL問合せを使用することもできます。
「ハッシュ結合で共通ディクショナリ・エンコーディングが使用される場合」では、SQL監視の出力を解釈する方法について説明しています。
前提条件
結合グループを監視するには、次の前提条件を満たしている必要があります。
-
結合グループが存在する必要があります。
-
結合グループによって参照される列が、結合グループの作成後に移入されている必要があります。
-
結合グループを使用可能な結合問合せを実行する必要があります。
結合グループの使用を監視するには:
-
必要な権限があるユーザーとしてデータベースにログインします。
-
次のようにして、SQL IDを格納するSQL*Plus変数を作成します。
VAR b_sqlid VARCHAR2(13)
-
結合グループ内の列で結合する問合せを実行します。
-
次のどちらかの方法を使用します。
-
グラフィカルなSQL監視レポート
SQL監視レポートはEnterprise Managerで使用できます。SQL*Plusでは、次のように
DBMS_SQL_MONITOR.REPORT_SQL_MONITOR
を使用すると、SQL監視レポートを生成できます。SET TRIMSPOOL ON SET TRIM ON SET PAGES 0 SET LINESIZE 1000 SET LONG 1000000 SET LONGCHUNKSIZE 1000000 SPOOL /tmp/long_sql.htm SELECT DBMS_SQL_MONITOR.REPORT_SQL_MONITOR( sql_id => :b_sqlid, report_level => 'ALL', TYPE => 'active') FROM DUAL; SPOOL OFF
ブラウザでレポートにアクセスし、ハッシュ結合の双眼鏡アイコンをクリックして、結合グループの統計を表示します。
-
コマンドラインでの問合せ
問合せで、
DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML
ファンクションを使用します。次に例を示します。SELECT encoding_hj.rowsource_id row_source_id, CASE WHEN encoding_hj.encodings_observed IS NULL AND encoding_hj.encodings_leveraged IS NOT NULL THEN 'join group was leveraged on ' || encoding_hj.encodings_leveraged || ' processes' ELSE 'join group was NOT leveraged' END columnar_encoding_usage_info FROM (SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML(session_id=>-1,sql_id=>:b_sqlid). EXTRACT(q'#//operation[@name='HASH JOIN' and @parent_id]#') xmldata FROM DUAL) hj_operation_data, XMLTABLE('/operation' PASSING hj_operation_data.xmldata COLUMNS "ROWSOURCE_ID" NUMBER PATH '@id', "ENCODINGS_LEVERAGED" NUMBER PATH 'rwsstats/stat[@id="9"]', "ENCODINGS_OBSERVED" NUMBER PATH 'rwsstats/stat[@id="10"]') encoding_hj;
-
SQL監視レポートを使用した結合グループの監視: 例
グラフィカルなSQL監視レポートを使用して、問合せで結合グループが利用されたかどうかを判断できるようにします。
この例では、sh.products
表およびsh.sales
表のprod_id
列で結合グループを作成してから、これらの表をこの列で結合します。sh
アカウントに管理権限を付与します。
例8-3 SQL監視レポートを使用した結合グループの監視
-
SQL*Plusで、ユーザー
sh
としてデータベースにログインします。 -
SQL IDを格納するためのSQL*Plus変数を次のように作成します。
VAR b_sqlid VARCHAR2(13)
-
次のように
INMEMORY
属性をsh.products
表およびsh.sales
表に適用します。ALTER TABLE sales NO INMEMORY; ALTER TABLE products NO INMEMORY; ALTER TABLE sales INMEMORY MEMCOMPRESS FOR QUERY; ALTER TABLE products INMEMORY MEMCOMPRESS FOR QUERY;
-
prod_id
で結合グループを作成します。CREATE INMEMORY JOIN GROUP jgrp_products_sales (products(prod_id), sales(prod_id));
-
それらの表をスキャンしてIM列ストアに移入します。
SELECT /*+ FULL(s) */ COUNT(*) FROM sales s; SELECT /*+ FULL(p) */ COUNT(*) FROM products p;
-
prod_id
列で結合する問合せを実行してから、商品売上を集計します。SELECT /*+ USE_HASH(sales) LEADING(products sales) MONITOR */ products.prod_id, products.prod_category_id, SUM(sales.amount_sold) FROM products, sales WHERE products.prod_id = sales.prod_id GROUP BY products.prod_category_id, products.prod_id;
-
DBMS_SQLTUNE.REPORT_SQL_MONITOR
を使用して、HTMLベースのSQL監視レポートを生成します。たとえば、次に示す内容のSQLスクリプトを作成して、SQL*Plusで実行します。
SET TRIMSPOOL ON SET TRIM ON SET PAGES 0 SET LINESIZE 1000 SET LONG 1000000 SET LONGCHUNKSIZE 1000000 SPOOL /tmp/jg_report.htm SELECT DBMS_SQL_MONITOR.REPORT_SQL_MONITOR( sql_id => :b_sqlid, report_level => 'ALL', TYPE => 'active') FROM DUAL; SPOOL OFF
-
ブラウザで、HTMLレポートを開きます。
次のレポート例は、結合の実行計画を示しています。ハッシュ結合の双眼鏡アイコンで、追加の統計が示されるウィンドウを開きます。
-
双眼鏡アイコンをクリックして、結合グループの統計を表示するウィンドウを開きます。
次に、統計が表示されたウィンドウの例を示します。
Columnar Encodings Leveraged
が正の値であり、Columnar Encodings Observed
が存在していないことから、結合グループが利用されたことがわかります。 -
必要に応じて、この例の後でクリーン・アップを実行します。
DROP INMEMORY JOIN GROUP jgrp_products_sales; ALTER TABLE sales NO INMEMORY; ALTER TABLE products NO INMEMORY;
関連項目:
-
DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML
関数について学習するには、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照 -
V$SESSION
ビューについて学習するには、『Oracle Databaseリファレンス』を参照
コマンドラインからの結合グループの監視: 例
コマンドライン・ツールを使用して、問合せで結合グループが利用されたかどうかを判断できるようにします。
この例では、sh.products
表およびsh.sales
表のprod_id
列で結合グループを作成してから、これらの表をこの列で結合します。sh
アカウントに管理権限を付与します。
例8-4 コマンドラインからの結合グループの監視
-
sh
としてデータベースにログインします。 -
SQL IDを格納するためのSQL*Plus変数を次のように作成します。
VAR b_sqlid VARCHAR2(13)
-
次のように
INMEMORY
属性をsh.products
表およびsh.sales
表に適用します。ALTER TABLE sales NO INMEMORY; ALTER TABLE products NO INMEMORY; ALTER TABLE sales INMEMORY MEMCOMPRESS FOR QUERY; ALTER TABLE products INMEMORY MEMCOMPRESS FOR QUERY;
-
prod_id
で結合グループを作成します。CREATE INMEMORY JOIN GROUP jgrp_products_sales (products(prod_id), sales(prod_id));
-
それらの表をスキャンしてIM列ストアに移入します。
SELECT /*+ FULL(s) */ COUNT(*) FROM sales s; SELECT /*+ FULL(p) */ COUNT(*) FROM products p;
-
prod_id
列で結合する問合せを実行してから、商品売上を集計します。SELECT /*+ USE_HASH(sales) LEADING(products sales) MONITOR */ products.prod_id, products.prod_category_id, SUM(sales.amount_sold) FROM products, sales WHERE products.prod_id = sales.prod_id GROUP BY products.prod_category_id, products.prod_id;
-
前述の集計問合せのSQL IDを取得します。
BEGIN SELECT PREV_SQL_ID INTO :b_sqlid FROM V$SESSION WHERE SID=USERENV('SID'); END;
-
DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML
を使用して、データベースで結合グループが使用されたかどうかを判断します。たとえば、次の問合せを実行します。
COL row_source_id FORMAT 999 COL columnar_encoding_usage_info FORMAT A40 SELECT encoding_hj.rowsource_id row_source_id, CASE WHEN encoding_hj.encodings_observed IS NULL AND encoding_hj.encodings_leveraged IS NOT NULL THEN 'join group was leveraged on ' || encoding_hj.encodings_leveraged || ' processes' ELSE 'join group was NOT leveraged' END columnar_encoding_usage_info FROM (SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML(session_id=>-1,sql_id=>:b_sqlid). EXTRACT(q'#//operation[@name='HASH JOIN' and @parent_id]#') xmldata FROM DUAL ) hj_operation_data, XMLTABLE('/operation' PASSING hj_operation_data.xmldata COLUMNS "ROWSOURCE_ID" NUMBER PATH '@id', "ENCODINGS_LEVERAGED" NUMBER PATH 'rwsstats/stat[@id="9"]', "ENCODINGS_OBSERVED" NUMBER PATH 'rwsstats/stat[@id="10"]' ) encoding_hj;
次の出力例は、問合せで結合グループが利用されたことを示しています。
ROW_SOURCE_ID COLUMNAR_ENCODING_USAGE_INFO ------------- ---------------------------------------- 2 join group was leveraged on 1 processes
-
必要に応じて、例の後にクリーン・アップを実行します。
DROP INMEMORY JOIN GROUP jgrp_products_sales; ALTER TABLE sales NO INMEMORY; ALTER TABLE products NO INMEMORY;
関連項目:
-
DBMS_SQLTUNE.REPORT_SQL_MONITOR_XML
関数について学習するには、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照 -
V$SESSION
ビューについて学習するには、『Oracle Databaseリファレンス』を参照
RACクラスタでの結合グループの利用
RACクラスタ全体のグローバルなディクショナリがRACでサポートされるようになりました。
共通ディクショナリは、単一インスタンスのOracleデータベースおよびOracle RAC One Nodeデータベースにおいてインスタンス固有です。これらのシステムでは、行の配布が関係しない結合に対してのみ、結合グループ対応のハッシュ結合が有効になります。
Oracle RACクラスタでは、1つのRACクラスタ内のインスタンス間で共有される分散型グローバル・ディクショナリがサポートされています。これにより、RAC上の分散型結合に対して、結合グループ対応のハッシュ結合を利用できます。RACデータベースでCREATE INMEMORY JOIN GROUP
文を発行すると、オブジェクトの移入の一部としてRACレベルの分散型グローバル・ディクショナリが作成されます。
次の例について考えてみます。列sales.dealer_key
とdealership.dealership_key
に結合グループが作成されて、2つの表の間の結合キーとして使用されます。これらの表を含むインメモリー結合グループを作成すると、RACレベルの共通グローバル・ディクショナリがこれらの列に対して作成されます。次に示すとおり、使用方法を変更しなくても、この拡張機能を利用できます。
create inmemory join group jg1 (sales(dealer_key), dealership(deadlership_key));
これらの列にアクセスする問合せで、この結合グループを利用できます。
select sum(revenue) from sales s, dealership d where s.dealership_key = d.dealership_key;
RACレベルの分散型グローバル・ディクショナリにより、問合せのパフォーマンスを向上できます。RACレベルのグローバル・ディクショナリを利用した結合グループ対応ハッシュ結合を使用して実行すると、SSB (Star Schema Benchmark)のパフォーマンスが大幅に向上します。
インメモリー・ディープ・ベクトル化を使用した結合の最適化
インメモリー・ディープ・ベクトル化は、各SQL演算子内で物理演算子をパイプライン化し、SIMD手法を使用してベクトル化することにより、複雑なSQL演算子を最適化できます。この機能は、デフォルトでは有効化されています。
インメモリー・ディープ・ベクトル化について
インメモリー・ディープ・ベクトル化は、問合せプランの上位レベルの問合せ演算子のベクトル化をサポートするSIMDベースのフレームワークです。このフレームワークには、SIMD、ハードウェア・アクセラレーション、パイプライン実行などの最適化が含まれます。
インメモリー・ベクトル化結合機能は、ディープ・ベクトル化フレームワークのキーとなります。SIMDベクター処理を使用して、フレームワークは、ハッシュ、構築、プローブ、収集などのハッシュ結合の側面を最適化します。この最適化により、結合処理のパフォーマンスを100%以上改善できます。
インメモリー・ベクトル化結合機能はユーザーに対して透過的であり、計画の変更は必要ありません。最適化はデフォルトで有効になっていますが、INMEMORY_DEEP_VECTORIZATION
初期化パラメータをfalse
に設定することによって無効にできます。
関連項目:
-
SIMDベクトル化についてさらに学習するには、「CPUアーキテクチャ: SIMDベクター処理」を参照してください。
-
ハッシュ結合についてさらに学習するには、Oracle Database SQLチューニング・ガイドを参照してください。
インメモリー・ディープ・ベクトル化の仕組み
インメモリー・ディープ・ベクトル化フレームワークでは、ハッシュ結合のような高度で複雑なSQL演算子をより小さいカーネル・サイズの単位に分解します。
分解されたカーネルはSIMDベクトル化手法に適しています。データベースは、パイプライン形式でカーネルを実行して操作全体を高速化します。
関連項目:
SIMDベクトル化についてさらに学習するには、「CPUアーキテクチャ: SIMDベクター処理」を参照してください。
インメモリー・ベクトル化結合の仕組み
ベクトル化結合機能は、インメモリー・ディープ・ベクトル化フレームワークの重要側面です。
インメモリー・ベクトル化結合の仕組みは次のとおりです。
-
実行時に、データベースは、インメモリー・ディープ・ベクトル化がハッシュ結合の最適化に役立つかどうかを判断します。役立つ場合、データベースは次のステップに進みます。
ノート:
ベクトル化結合操作の選択は実行時に行われるため、実行計画に最適化は表示されません。
-
データベースは、インメモリー列データ形式で直接評価するためにスキャン演算子に結合処理をプッシュ・ダウンします。
-
この操作は、従来のハッシュ表ではなく、SIMD最適化ハッシュ表データ構造を使用します。
-
データベースは、結合の左側と右側で一致した行を判別し、ベクトル化手法を使用してそれらを親SQL演算子に戻します。
インメモリー・ベクトル化結合では、次のようなインメモリー機能を利用できます。
-
結合グループ
結合グループが宣言されている場合、ディープ・ベクトル化結合処理が大幅に高速化する可能性があります。
-
IM動的スキャン
結合処理は、スキャン演算子で軽量スレッドを使用してさらにパラレル化されます。
-
集計のプッシュダウン
結合の最上位の集計が、結合操作を使用してベクトル化されます。
-
インメモリー列圧縮形式
ベクトル化結合機能では、列データ形式が頻繁に利用されます。
ディープ・ベクトル化のユーザー・インタフェース
ディープ・ベクトル化フレームワークは、INMEMORY_DEEP_VECTORIZATION
初期化パラメータがtrue
(デフォルト値)の場合に有効になります。
SQL監視を使用して、問合せがベクトル化結合を使用しているかどうかを判断できます。SQL監視レポートで、「情報」列のHASH JOIN
操作の横にある双眼鏡アイコンをクリックします。DeepVec Hash Joins
の値が1
の場合は、問合せでディープ・ベクトル化が使用されています。それ以外の場合は、問合せで使用されていません。
ディープ・ベクトル化フレームワークでサポートされる問合せタイプ
次のものを含む問合せが、インメモリー・ディープ・ベクトル化フレームワークでサポートされています:
- 複数の結合キー列
- セミ結合と外部結合
- 次の関数ベースの集計:
集計も完全にサポートされています。これには次のものが含まれます:
- 構築側、または構築および調査側の組合せからの列。
- 列または集計をグループ化する単純な式。
インメモリー・ベクトル化結合: 例
この例は、ディープ・ベクトル化がハッシュ結合にどのように役立っているかを示しています。
この例では、customers
およびorders
表が存在し、INMEMORY_DEEP_VECTORIZATION
が現在false
に設定されています。目標は、可能な場合はディープベクトル化の最適化を利用して、単一の国内の注文をカウントすることです
-
管理ユーザー
DB1
としてデータベースにログインします。 -
ALTER SESSION
を使用して、INMEMORY_DEEP_VECTORIZATION
初期化パラメータをENABLE
に設定します。 -
次に示すように、
tpch.customer
表とtpch.orders
表を結合します。tpch.customer.c_nationkey
列の値21
に対してフィルタ処理します。SELECT /*+monitor */ COUNT(*) FROM tpch.customer c, tpch.orders o WHERE c.c_custkey = o.o_custkey AND c.c_nationkey = 21
-
SQL MonitorレポートをHTMLで作成するには、SQL IDを
DBMS_SQL_MONITOR.REPORT_SQL_MONITOR
に渡します。レポートの生成方法を示す例は、「結合グループの使用の監視」を参照してください。
-
ブラウザで、SQL Monitorレポートを開きます。
レポートの概要セクションが下側に表示されます。
-
レポートの「詳細」セクションで、
HASH JOIN
操作を探して双眼鏡アイコンをクリックします。 -
「その他の情報」ウィンドウで、
DeepVec Hash Joins
を調べます。値が1
であるため、データベースではインメモリー・ベクトル化結合が使用されました。DeepVec Hash Join Flags
は、ディープ・ベクトル化がどの最適化を使用したかを示す内部統計であることに注意してください。
マルチレベル結合のためのインメモリー・ディープ・ベクトル化
インメモリー・ディープ・ベクトル化の機能拡張により、複数表の結合および集計を実行する複雑な問合せがサポートされるようになりました。
ノート:
現在、ハッシュ結合計画はサポートされていません。インメモリー・ディープ・ベクトル化の他の側面と同様に、マルチレベル結合のベクトル化はユーザーに対して透過的であり、計画の変更は必要ありません。
結合では、次のような複数の結合キー列がサポートされています。
select * from build, probe
where build.key1 = probe.key1
and build.key2 = probe.key2
and …
select orders_order_id, avg(lineitem_extendedprice)
from orders, lineitem
where orders.zipcode = lineitem.zipcode
and orders.city = lineitem.city
group by orders.order_id;
オプティマイザでサポートされているマルチレベル結合のタイプ
オプティマイザによって生成されるマルチレベル結合には、次の2つのタイプがあります:
- 左側の深い結合
各結合ノードの結果は、その親結合の構築側にフィードされます
- 右側の深い結合
各結合ノードの結果は、その親結合の調査側にフィードされます

図inmem_multileveljoins.epsの説明