Upgrade to Pro — share decks privately, control downloads, hide ads and more …

【Oracle Developer Day 2026】SQL性能改善の武器としてのパラレル実...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

【Oracle Developer Day 2026】SQL性能改善の武器としてのパラレル実行:実行計画で見抜く“効く/効かない”パターン

2026/05/21
[T2-3] SQL性能改善の武器としてのパラレル実行
- 実行計画で見抜く“効く/効かない”パターン
Oracle DatabaseのSQL性能改善における強力な武器であるパラレル実行を、実務目線で踏み込んで解説します。パラレル実行を用いると、多くのケースでSQLを書き換えずに、ヒントや設定の付与だけで、処理を並列化でき、大きな性能改善が期待できます。一方で、より確実に効果を引き出すには、データの分散(distribution)やデータの偏り(skew)、TEMP使用といった特性を理解し、状況に応じて設計・調整することが重要です。
本セッションでは、パラレル実行の内部動作を整理したうえで、効果が出にくいケースに遭遇した際も、実行計画などから状況を読み解き、どう手を打つかを紹介します。

辻 研一郎
日本オラクル株式会社

Avatar for oracle4engineer

oracle4engineer PRO

May 22, 2026

More Decks by oracle4engineer

Transcript

  1. 辻 研一郎 (Kenichiro Tsuji) Kenichiro Tsuji Princapal Cloud Engineer 2

    Copyright © 2026, Oracle and/or its affiliates 日本オラクル株式会社 製品事業統括 AI Data Platform COE本部 データベース・ソリューション部 プリンシパル クラウド エンジニア
  2. アジェンダ 3 Copyright © 2026, Oracle and/or its affiliates 1.

    SQLのパラレル実行のイメージをつかむ 2. パラレル実行の課題1:データ・スキュー 3. パラレル実行の課題2:パラレル間データ通信 4. まとめ
  3. OracleのSQLのパラレル実行とは 5 Copyright © 2026, Oracle and/or its affiliates SQLのパラレル実行は、SQL文の内容はそのままで、複数プロセス(複数CPU)で実行して高速化する方法

    次のような場面ではパラレル実行が活躍できます ・大量データ処理 ・多重度が低い(同時実行SQLが少ない)状況 バッチ処理やDWH なぜ、今パラレル実行なのか? 十数年前:CPU数に対してストレージ能力が足らず、IOネックになる状況が多い。パラレル度をあげても性能が上がらない 2026年現在:IOネックを解消する方法(フラッシュストレージ、Exadata、Autonomous DBなど) の登場でパラレル実行が真価を発揮しやすくなった このセッションでは、IOネックを超えた先でパラレル実行に真価を発揮させるときにぶつかるデータ・スキュー(データの偏り)、 パラレル間データ通信に踏み込んでいきます
  4. OracleのSQLのパラレル実行の基本イメージ 6 Copyright © 2026, Oracle and/or its affiliates パラレル実行のイメージを掴む

    こちらはシリアル実行の実行計画です、これをパラレル度4でパラレル実行するとどうなると思いますか? SQL> SELECT c1, count(*) cnt FROM tab02 2 GROUP BY c1 ORDER BY cnt; 実行計画 -------------------------------------- Plan hash value: 774632932 -------------------------------------- | Id | Operation | Name | -------------------------------------- | 0 | SELECT STATEMENT | | | 1 | SORT ORDER BY | | | 2 | HASH GROUP BY | | | 3 | TABLE ACCESS FULL| TAB02 |
  5. OracleのSQLのパラレル実行の基本イメージ 7 Copyright © 2026, Oracle and/or its affiliates パラレル実行のイメージを掴む

    こちらはシリアル実行の実行計画です、これをパラレル度4でパラレル実行するとどうなると思いますか? SQL> SELECT c1, count(*) cnt FROM tab02 2 GROUP BY c1 ORDER BY cnt; 実行計画 -------------------------------------- Plan hash value: 774632932 -------------------------------------- | Id | Operation | Name | -------------------------------------- | 0 | SELECT STATEMENT | | | 1 | SORT ORDER BY | | | 2 | HASH GROUP BY | | | 3 | TABLE ACCESS FULL| TAB02 | パラレル度4 パラレル度4 パラレル度4 考え方1 実行計画のそれぞれのオペレーションをパラレル実行する(イントラ・オペレーション並列化) PX スキャン 表 イントラ・オペレーション並列化 PX PX PX GroupBy PX PX PX PX QC PX PX PX PX OrderBy それぞれのオペレーションをイントラ・オ ペレーションでパラレル実行する単位を PXサーバーセット(PXセット) といいます PXセット0 PXセット1 PXセット2
  6. OracleのSQLのパラレル実行の基本イメージ 8 Copyright © 2026, Oracle and/or its affiliates パラレル実行のイメージを掴む

    これはシリアル実行の実行計画です、これをパラレル度4でパラレル実行するとどうなると思いますか? SQL> SELECT c1, count(*) cnt FROM tab02 2 GROUP BY c1 ORDER BY cnt; 実行計画 -------------------------------------- Plan hash value: 774632932 -------------------------------------- | Id | Operation | Name | -------------------------------------- | 0 | SELECT STATEMENT | | | 1 | SORT ORDER BY | | | 2 | HASH GROUP BY | | | 3 | TABLE ACCESS FULL| TAB02 | パラレル度4 パラレル度4 パラレル度4 考え方1 実行計画のそれぞれのオペレーションをパラレル実行する(イントラ・オペレーション並列化) PX スキャン 表 イントラ・オペレーション並列化 PX PX PX GroupBy PX PX PX PX QC PX PX PX PX OrderBy 考え方2 オペレーションをまたがってパラレル実行する(インター・オペレーション並列化) 両方発生します ①スキャンしながら GroupBy ②GroupByしながら OrderBy イ ン タ ー ・ オ ペ レ ー シ ョ ン 並 列 化 ① ② QCごとにPXセットは最 大2セット同時実行しま す。つまり、最大でパラレ ル度×2のプロセス数での 実行となります 前のPXセットの結果を入力として、次のPXセットが処理していくモ デルをプロデューサ/コンシューマ・モデルと呼びます
  7. パラレル実行の動作イメージを実行計画からつかむ 9 Copyright © 2026, Oracle and/or its affiliates ------------------------------------------------------------------------------------

    | Id | Operation | Name | TQ | IN-OUT | PQ Distrib | ------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) |:TQ10001| Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH |:TQ10000| Q1,00 | P->P | HASH | | 6 | HASH GROUP BY | | Q1,00 | PCWP | | | 7 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 8 | TABLE ACCESS FULL| EMP | Q1,00 | PCWP | | ------------------------------------------------------------------------------------ 実行計画にあるパラレル実行独自のPX xxx、TQxxxx、TQ、IN-OUT、PQ Distribを利用して、PXセッ トから次のPXセットへデータを渡す流れのイメージをつかみます。 要素が多いですが、P→Pに注目するところから始めると楽です SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id;
  8. パラレル実行の動作イメージを実行計画からつかむ 10 Copyright © 2026, Oracle and/or its affiliates -------------------------------------------------------------------------

    | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 7 | TABLE ACCESS FULL| SALES | Q1,00 | PCWP | | ------------------------------------------------------------------------- ① P→Pに注目します。P→P(Prallel to Parallel)はPXセットが次のPXセットにデータを 送るという意味で、各PXセットの処理の境目と なります SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id;
  9. IN-OUT列 11 Copyright © 2026, Oracle and/or its affiliates プロセス間通信

    プロセス間通信する方式 P->P: Parallel to Parallel • PXが次のPXサーバー・セットに データを送る P->S: Parallel to Serial • PXがQCにデータを送る S->P: Serial to Parallel • QCがPXにデータを送る • このステップはシリアル実行 プロセス間通信しない方式 PCWP: Parallel Combined with Parent • 次のステップも同一のPXが行なう PCWC: Parallel Combined with Child • 前のステップと同一のPXが行なう こちらの2つが出ている間はPXセット間で通信 が発生していない。 つまり同じPXセットで処理しつづけていることに なります
  10. パラレル実行の動作イメージを実行計画からつかむ 12 Copyright © 2026, Oracle and/or its affiliates -------------------------------------------------------------------------

    | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 7 | TABLE ACCESS FULL| SALES | Q1,00 | PCWP | | ------------------------------------------------------------------------- SALES PX PX TQ10000 PX PX TQ10001 QC PXセット00 PXセット01 ②後ろの2桁の数字がPXセットの番号に該当、 TQの後ろ2桁も同様。Q1はQCの番号 ②TQの後ろ2桁の数字、もしくはTQ名の後ろ2 桁がPXセットの番号です。Q1はQCの番号。① の線を境に番号が変わっていることを確認。PX セットの番号ごとに背景色を変えます TQはPXセットの実行結果を次のPXセットに渡す ための置き場のイメージ(※) SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id; (※)TQの補足 TQ:テーブル・キューは抽象概念で実際に メモリ上にテーブルのような形で用意されるわ けではありません。 実際には各プロセスがそれぞれキューを持っ ており、そこに置かれたデータをキュー・リファレ ンスという番号を使ってリンクしていています。 読み取ったデータは各プロセスのPGAから PGAに直接コピーされます
  11. パラレル実行の動作イメージを実行計画からつかむ 13 Copyright © 2026, Oracle and/or its affiliates -------------------------------------------------------------------------

    | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 7 | TABLE ACCESS FULL| SALES | Q1,00 | PCWP | | ------------------------------------------------------------------------- SALES PX PX スキャン担当 TQ10000 PX PX GROUP BY担当 TQ10001 QC PXセット00 PXセット01 ③ それぞれのPXセッ ト内の実行計画から どんな処理をパラレル 実行しているかつかむ ③ それぞれのPXセッ ト内の実行計画から どんな処理をパラレル 実行しているかつかむ SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id; Tips: リアルタイムSQL監視では、PXセットご とに先頭の人マーク部分で色分けされ ています
  12. パラレル実行の動作イメージを実行計画からつかむ 14 Copyright © 2026, Oracle and/or its affiliates -------------------------------------------------------------------------

    | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 7 | TABLE ACCESS FULL| SALES | Q1,00 | PCWP | | ------------------------------------------------------------------------- SALES PX PX スキャン担当 TQ10000 PX PX GROUP BY担当 TQ10001 QC PXセット00 PXセット01 PX BLOCK ITERATOR PX SEND HASH PX SEND QC (RANDOM) QC(RAND) 処理が終わった順にTQにおく ④PX XXX関連のオ ペレーションの役割に ついて把握する SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id; PX RECEIVE
  13. スキャン時のPXへのデータ割り当て方式 15 Copyright © 2026, Oracle and/or its affiliates ブロック・レンジ・グラニュルとパーティション・グラニュル

    ブロック・レンジ・グラニュル • PX BLOCK ITERATOR • ブロック単位で分割してアクセス • パーティション表に対してもブロック・レンジ・グラニュル は使用されることはあります パーティション・グラニュル • PX PARTITION RANGE ALL • PX PARTITION HASH ALL • パーティション単位の論理分割を利用したい場合 • パーティション単位に分割してアクセス - パーティション・ワイズ結合など - インデックス・スキャンのパラレル実行でも利用 • インデックス・ファースト・フル・スキャンでなくとも パーティションであればパラレルインデックススキャンが可能 PX スキャン PX PX PX QC P1 表 P2 P3 P4 PX スキャン PX PX PX QC 表
  14. PX SEND xxxまたはPQ Distrib 列 16 Copyright © 2026, Oracle

    and/or its affiliates P->Pでの分散方式のみ抜粋 HASH(基本はこれを使用する) • 大量のデータを分割するのに最適。ハッシュ分散し、同じキーを同じPXへ送る • 結合やGroup Byでの基本的な方式 • 重複データが多いときに、データの偏り(データ・スキュー)が発生 BROADCAST(結合の片方が小さい) • 結合で片方が小さい場合利用される方式 • 小さい方のデータセットをすべてのPXに配布 RANGE(ソートなど) • ソート・キーで分散、PXへの配分をキー順を保ったレンジで分ける ROUND-ROBIN • 行を順番にPXに配る方式 • PXへのデータの均等配布目的で使用 PARTITION • パーティション分割(片方がパーティション表のときのパーシャル・パーティション・ワイズ結合)
  15. データ・スキュー 18 Copyright © 2026, Oracle and/or its affiliates データ・スキューとPX間処理量のかたよりが起こす性能問題

    PX1 PX2 PX3 PX4 理想的なパラレル実行 各PXに対して処理するデータ量が同じ。 各PXの処理が同時に終わり、PXの待ちが発生しない PX1 PX2 PX3 PX4 データ・スキューが発生している場合 各PXで処理するデータ量が異なる 偏りが大きいPXの終了を、他のPXが待つ形になる PX SEND HASHでは、結合キーや集約キーのハッシュ値で各 行の送り先PXが決まります。キー値に偏りがあると、同じキーの 行は同じPXに集まるため、一部のPXだけが大量の行を処理し、 そこがボトルネックになります。
  16. 結合(HASH JOIN)でのPX SEND HASHのスキュー発生 19 Copyright © 2026, Oracle and/or

    its affiliates -------------------------------------------------------------------------- | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10002 | Q1,02 | P->S | QC (RAND) | |* 3 | HASH JOIN | | Q1,02 | PCWP | | | 4 | PX RECEIVE | | Q1,02 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 7 | TABLE ACCESS FULL| CUSTOMERS | Q1,00 | PCWP | | | 8 | PX RECEIVE | | Q1,02 | PCWP | | | 9 | PX SEND HASH | :TQ10001 | Q1,01 | P->P | HASH | | 10 | PX BLOCK ITERATOR | | Q1,01 | PCWC | | |* 11 | TABLE ACCESS FULL| SALES | Q1,01 | PCWP | | -------------------------------------------------------------------------- SELECT c.cust_email FROM sales s, customers c WHERE s.cust_id = c.cust_id AND s.amount_sold >= 1000 以下のSQLの実行計画を例に具体的なケースをみていきます データ・スキューの問題をみるため、特定顧客の注文が多いようなケースを想定します SALES表には特定顧客ID(例えばcustomer_id=1)の注文データが多数を占めている状況をイメージをしてく ださい
  17. 結合(HASH JOIN)でのPX SEND HASHのスキュー発生 20 Copyright © 2026, Oracle and/or

    its affiliates SALES PX PX スキャン担当 TQ10001 PXセット01 PX BLOCK ITERATOR PX SEND HASH CUSTOMERS PX PX スキャン担当 TQ10000 PXセット00 PX BLOCK ITERATOR PX SEND HASH PX PX QC PXセット02 TQ10002 ハッシュジョイン担当 ビルド プローブ スキューにより上のPXのハッ シュ・ジョインの方が重い スキュー発生 PX RECEIVE PX RECEIVE
  18. V$PQ_TQSTATによるスキューの観測方法 21 Copyright © 2026, Oracle and/or its affiliates 各PXセットのProducerとComsumerのPX毎の行数がわかるためスキューの具合がわかります

    select tq_id,server_type,num_rows,process from v$pq_tqstat order by tq_id,server_type desc,process; TQ_ID SERVER_TYP NUM_ROWS PROCES ---------- ---------- ---------- ------ 0 Producer 0 P002 0 Producer 5 P003 0 Consumer 2 P000 0 Consumer 3 P001 1 Producer 54353 P002 1 Producer 45647 P003 1 Consumer 2 P000 1 Consumer 99998 P001 2 Producer 1 P000 2 Producer 1 P001 2 Consumer 2 QC 外部表 CUSTOMERS側 内部表 SALES側 PX BLOCK ITERATOR PX RECEIVE= PX SEND HASH PX RECEIVE= PX SEND HASH PX BLOCK ITERATOR Tips: リアルタイムSQL監視では、各PXセット内でPX毎の DB Time/IO Count/Buffer Getsを確認するこ とで、スキューの発生を観測することができます スキュー発生
  19. 解決策:BROADCASTによるデータ・スキュー解決 22 Copyright © 2026, Oracle and/or its affiliates 大きな表と小さな表の結合のときにオプティマイザが判断して実行

    小さい表を、大きい表側をスキャンした各PXに配布(BROADCAST)し、その場で結合 • スキューを回避した形でハッシュジョインの並列化が可能 • 大きい表側のSEND HASHを防ぐことで、スキューの発生を防ぐだけでなく、PX間データ送信も防ぐ -------------------------------------------------------------------------- | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | |* 3 | HASH JOIN | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND BROADCAST | :TQ10000 | Q1,00 | P->P | BROADCAST | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | |* 7 | TABLE ACCESS FULL| COUNTRIES | Q1,00 | PCWP | | | 8 | PX BLOCK ITERATOR | | Q1,01 | PCWC | | | 9 | TABLE ACCESS FULL | CUSTOMERS | Q1,01 | PCWP | | -------------------------------------------------------------------------- SELECT cu.cust_email FROM customers cu, countries co WHERE cu.country_id = co.country_id AND co.country_region = 'Asia'
  20. 解決策:BROADCASTによる解決 23 Copyright © 2026, Oracle and/or its affiliates 外部表をスキャンした

    PXセットがハッシュジョイ ンも実行することで SEND HASHを回避 Tips: 統計情報が不正確で、BROADCASTした データセットが、実は大きかった場合、PX間 通信がボトルネックになります。 このトピックは後ででてきます CUSTOMERS PX PX スキャン&ハッシュジョイン担当 PXセット01 PX BLOCK ITERATOR COUNTRIES PX PX スキャン担当 TQ10000 PXセット00 PX BLOCK ITERATOR QC TQ10001 PX SEND BROADCAST PX SEND QC(RANDOM) PX RECEIVE
  21. 解決策:Small Table Replicate(12c以降) 24 Copyright © 2026, Oracle and/or its

    affiliates 小さい表はPXセット作ってBROADCASTしなくとも、その場で読めばいいという発想 CUSTOMERS PX PX スキャン&ハッシュジョイン担当 PXセット00 PX BLOCK ITERATOR COUNTRIES QC TQ10001 COUNTRIES PX SEND QC(RANDOM) PXセット00が小さい表(COUNTRIES)を読 み取ることで、PX BROADCASTも回避
  22. データ・スキューへのSQLでの対策:ホット・キー分離 25 Copyright © 2026, Oracle and/or its affiliates ホットキー側はBROADCAST、非ホット・キー側はPX

    SEND HASH ホット・キーとはデータが偏って多くの行をしめているキーのこと。 SELECT c.customer_segment, SUM(s.amount) AS amount_sum FROM sales_fact s JOIN dim_customer c ON c.customer_id = s.customer_id WHERE s.sales_date >= DATE '2026-05-01' AND s.sales_date < DATE '2026-06-01' GROUP BY c.customer_segment; サンプルSQL(ホット・キー分離前) • ホット・キーはcustomer_id=1,2(これは割り出せていることが前提) • 主要取引先がほぼ決まっているような想定 SQL書き換え方針: • 元のSQLを、ホット・キー側と非ホット・キー側にわけてUNIONする • ホットキー側はBROADCAST、非ホット・キー側はPX SEND HASHを期待
  23. データ・スキューへのSQLでの対策の例 26 Copyright © 2026, Oracle and/or its affiliates ホット・キー分離

    /* customer_id=1,2がホット・キー */ WITH hot_keys AS ( SELECT 1 AS customer_id FROM dual UNION ALL SELECT 2 AS customer_id FROM dual ) SELECT customer_segment, SUM(amount_sum) AS amount_sum FROM ( /* ホットキー用ブランチ */ SELECT c.customer_segment, SUM(s.amount) AS amount_sum FROM sales_fact s JOIN dim_customer c ON c.customer_id = s.customer_id WHERE s.sales_date >= DATE '2026-05-01' AND s.sales_date < DATE '2026-06-01' AND EXISTS ( SELECT 1 FROM hot_keys hk WHERE hk.customer_id = s.customer_id ) GROUP BY c.customer_segment UNION ALL /* 非ホットキー用ブランチ*/ SELECT c.customer_segment, SUM(s.amount) AS amount_sum FROM sales_fact s JOIN dim_customer c ON c.customer_id = s.customer_id WHERE s.sales_date >= DATE '2026-05-01' AND s.sales_date < DATE '2026-06-01' AND NOT EXISTS ( SELECT 1 FROM hot_keys hk WHERE hk.customer_id = s.customer_id ) GROUP BY c.customer_segment ) GROUP BY customer_segment; につづく
  24. データ・スキューへのSQLでの対策の例 27 Copyright © 2026, Oracle and/or its affiliates ホット・キー分離

    /* customer_id=1,2がホット・キー */ WITH hot_keys AS ( SELECT 1 AS customer_id FROM dual UNION ALL SELECT 2 AS customer_id FROM dual ) SELECT customer_segment, SUM(amount_sum) AS amount_sum FROM ( /* ホットキー用ブランチ */ SELECT c.customer_segment, SUM(s.amount) AS amount_sum FROM sales_fact s JOIN dim_customer c ON c.customer_id = s.customer_id WHERE s.sales_date >= DATE '2026-05-01' AND s.sales_date < DATE '2026-06-01' AND EXISTS ( SELECT 1 FROM hot_keys hk WHERE hk.customer_id = s.customer_id ) GROUP BY c.customer_segment UNION ALL /* 非ホットキー用ブランチ*/ SELECT c.customer_segment, SUM(s.amount) AS amount_sum FROM sales_fact s JOIN dim_customer c ON c.customer_id = s.customer_id WHERE s.sales_date >= DATE '2026-05-01' AND s.sales_date < DATE '2026-06-01' AND NOT EXISTS ( SELECT 1 FROM hot_keys hk WHERE hk.customer_id = s.customer_id ) GROUP BY c.customer_segment ) GROUP BY customer_segment; ホット・キー側はBROADCAST HASH JOIN PX RECEIVE PX SEND BROADCAST -- DIM_CUSTOMER側 TABLE ACCESS FULL DIM_CUSTOMER PX BLOCK ITERATOR -- SALES_FACT側 TABLE ACCESS FULL SALES_FACT 非ホット・キー側はPX SEND HASH HASH JOIN PX RECEIVE -- DIM_CUSTOMER側 PX SEND HASH PX RECEIVE -- SALES_FACT側 PX SEND HASH Tips: 実は、SQLはそのままで、これと似た動作をする機能が12cからあ ります。PX SEND HYBRID HASH(SKEW)です(後述) につづく
  25. パラレル間データ通信 29 Copyright © 2026, Oracle and/or its affiliates PXセット間の通信で問題が発生するケース

    PXセット間の通信で問題が発生するケースを 扱います 問題が発生する代表例: SEND HASHすべき大きめの表を BROADCASTしてしまった また、PXセット間の通信を抑えるために使える オラクルの機能も紹介します • GROUP BY PUSH DOWN • パーティション・ワイズ結合 ここ ここ
  26. 適応型パラレル分散方法:PX SEND HYBRID HASH(12c以降) 30 Copyright © 2026, Oracle and/or

    its affiliates 見積もりミスによる大きいデータのBROADCASTを防ぐ 適応型パラレル分散方法: オプティマイザが統計情報だけでは、正確に見積もれないと判断した場合、実行計画作成時点では 分散方法を決定せず、実行時の行数を考慮して、分散方法を決定する機能 ハッシュジョインの外部表側の 行数が多ければ HASH 行数が少なければ BROADCAST 判断の閾値は、外部表側の実際の行数がパラレル度の2倍 これによって、実際に行数が多い場合に、誤ってBROADCASTされてしまうことを抑制できます 適応計画(Adaptive Plans)の機能のひとつ。デフォルト有効(19c,26ai)
  27. 適応型パラレル分散方法:PX SEND HYBRID HASH 31 Copyright © 2026, Oracle and/or

    its affiliates 実行計画の分散方法の確認 SQL> SELECT COUNT(*) FROM ( SELECT /*+ pq_distribute(t1,hash,hash) */ * FROM t3,t1 WHERE t3.col1 = t1.col1); ----------------------------------------------------------------------------------------------- ---------- | Id | Operation | Name | E-Rows | TQ |IN-OUT| PQ Distrib | A-Rows | | A-Rows | ----------------------------------------------------------------------------------------------- ---------- | 0 | SELECT STATEMENT | | | | | | 1 | | 1 | | 1 | SORT AGGREGATE | | 1 | | | | 1 | | 1 | | 2 | PX COORDINATOR | | | | | | 2 | | 4 | | 3 | PX SEND QC (RANDOM) | :TQ10002 | 1 | Q1,02 | P->S | QC (RAND) | 0 | | 0 | | 4 | SORT AGGREGATE | | 1 | Q1,02 | PCWP | | 2 | | 4 | |* 5 | HASH JOIN | | 50000 | Q1,02 | PCWP | | 100K| | 100K| | 6 | PX RECEIVE | | 5 | Q1,02 | PCWP | | 5 | | 20 | | 7 | PX SEND HYBRID HASH | :TQ10000 | 5 | Q1,00 | P->P | HYBRID HASH| 0 | | 0 | | 8 | STATISTICS COLLECTOR | | | Q1,00 | PCWC | | 5 | | 5 | | 9 | PX BLOCK ITERATOR | | 5 | Q1,00 | PCWC | | 5 | | 5 | |* 10 | TABLE ACCESS FULL | T3 | 5 | Q1,00 | PCWP | | 5 | | 5 | | 11 | PX RECEIVE | | 100K| Q1,02 | PCWP | | 100K| | 100K| | 12 | PX SEND HYBRID HASH | :TQ10001 | 100K| Q1,01 | P->P | HYBRID HASH| 0 | | 0 | | 13 | PX BLOCK ITERATOR | | 100K| Q1,01 | PCWC | | 100K| | 100K| |* 14 | TABLE ACCESS FULL | T1 | 100K| Q1,01 | PCWP | | 100K| | 100K| 津島博士のパフォーマンス講座 第39回 https://blogs.oracle.com/otnjp/tsushima-hakushi-39 パラレル2 閾値 4 パラレル4 閾値 8 外部表側の件数は5件 外部表側の件数が 閾値より上:HASH 閾値より下:BROADCAST (閾値はパラレル度の2倍) HASH BROADCAST 5件 ×4 パラレル = 20 件 Tips: A-RowsのBROADCASTの件数に注意 各PXにBROADCASTして膨らんだ件数が 出力される Tips: リアルタイムSQL監視では、Other列の双眼 鏡アイコンからどの分散方法が選択されたか 確認できます。 Distribution method: 5:ROUND-ROBIN 6:BROADCAST 16:HASH
  28. 適応型パラレル分散方法:PX SEND HYBRID HASH 32 Copyright © 2026, Oracle and/or

    its affiliates 外部表側がBROADCASTになった場合は、内部表側はROUND-ROBIN 津島博士のパフォーマンス講座 第39回 https://blogs.oracle.com/otnjp/tsushima-hakushi-39 HYBRID HASHで外部表側がBROADCASTになった場合、内部表側 ではROUND-ROBINによって均等分散配布を行います。 通常のBROADCASTでは、内部表側をスキャンしたPXセットがそのまま ハッシュ・ジョインし、PX SEND処理を回避していましたが、 HYBRID HASHではそうはなりません。 これはHYBRID HASHでは、実行計画を立てた時点で、内部表のスキャ ンとハッシュジョインのPXセットは別と指定された上で、後から均等配布する ための制限と考えられます T1 PX PX スキャン担当 TQ10001 PXセット01 PX BLOCK ITERATOR T3 PX PX スキャン担当 TQ10000 PXセット00 PX BLOCK ITERATOR PX PX QC TQ10002 ハッシュジョイン担当 ビルド プローブ PX SEND HYBRID HASH (ROUND- ROBIN) PX SEND HYBRID HASH (BROADCAST) 外部表側 内部表側 参考:通常のBROADCASTのハッシュ・ジョイン PX RECEIVE PX RECEIVE PXセット02
  29. PQ SEND HYBRID HASH(SKEW) 33 Copyright © 2026, Oracle and/or

    its affiliates SQL変更なしで重複値の多いホット・キーにはBROADCAST、非ホット・キーはSEND HASHを実施 津島博士のパフォーマンス講座 第39回 https://blogs.oracle.com/otnjp/tsushima-hakushi-39 SQLのホット・キー分割をせずに、ホット・キー分割を実現 • ホット・キー側はBROADCAST • 非ホット・キー側はHASH 結合列にヒストグラムが存在するかPQ_SKEWヒントを使用していた場合に出現
  30. PQ SEND HYBRID HASH(SKEW) 34 Copyright © 2026, Oracle and/or

    its affiliates 実行計画 津島博士のパフォーマンス講座 第39回 https://blogs.oracle.com/otnjp/tsushima-hakushi-39 SQL> ALTER SESSION FORCE PARALLEL QUERY PARALLEL 2; SQL> SELECT COUNT(*) FROM (SELECT /*+ pq_distribute(t1,hash,hash) pq_skew(t1) */ * FROM t3,t1 WHERE t3.col1 = t1.col1); --------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | | TQ |IN-OUT| PQ Distrib | A-Rows | --------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | | | 1 | | 1 | SORT AGGREGATE | | 1 | 1 | | | | | 1 | | 2 | PX COORDINATOR | | 1 | | | | | | 2 | | 3 | PX SEND QC (RANDOM) | :TQ10002 | 0 | 1 | | Q1,02 | P->S | QC (RAND) | 0 | | 4 | SORT AGGREGATE | | 2 | 1 | | Q1,02 | PCWP | | 2 | |* 5 | HASH JOIN | | 2 | 50000 | | Q1,02 | PCWP | | 100K| | 6 | PX RECEIVE | | 2 | 5 | | Q1,02 | PCWP | | 6 | | 7 | PX SEND HYBRID HASH | :TQ10000 | 0 | 5 | | Q1,00 | P->P | HYBRID HASH| 0 | | 8 | STATISTICS COLLECTOR | | 2 | | | Q1,00 | PCWC | | 5 | | 9 | PX BLOCK ITERATOR | | 2 | 5 | | Q1,00 | PCWC | | 5 | |* 10 | TABLE ACCESS FULL | T3 | 1 | 5 | | Q1,00 | PCWP | | 5 | | 11 | PX RECEIVE | | 2 | 100K| | Q1,02 | PCWP | | 100K| | 12 | PX SEND HYBRID HASH (SKEW)| :TQ10001 | 0 | 100K| | Q1,01 | P->P | HYBRID HASH| 0 | | 13 | PX BLOCK ITERATOR | | 2 | 100K| | Q1,01 | PCWC | | 100K| |* 14 | TABLE ACCESS FULL | T1 | 26 | 100K| | Q1,01 | PCWP | | 100K| T3:全5行 (内部表側) COL1 COUNT(*) ---------- ---------- 1 1 2 1 3 1 4 1 100 1 T1:全100,000行 (外部表側) COL1 COUNT(*) ---------- ---------- 1 1 2 1 3 1 4 1 100 99996 ホット・キー → ホット・キー → ホット・キーの100は2パラレルに BROADCASTするので2 非ホット・キーは残り4つと 合わせて6 T1のSCANと別のPXセットで結合 するため、内部表側を均等配布す るのための、ROUND-ROBINは必 要
  31. PQ SEND HYBRID HASH(SKEW) 35 Copyright © 2026, Oracle and/or

    its affiliates v$pq_tqstatから確認 SQL> select tq_id,server_type,num_rows,process from v$pq_tqstat order by tq_id,server_type desc,process; TQ_ID SERVER_TYPE NUM_ROWS PROCESS ---------- -------------------- ---------- ---------- 0 Producer 6 P002 <-- 100を2個にして6行に 0 Producer 0 P003 0 Consumer 3 P000 <-- どちらにも100をいれる 0 Consumer 3 P001 <-- どちらにも100をいれる 1 Producer 49903 P002 1 Producer 50097 P003 1 Consumer 50001 P000 1 Consumer 49999 P001 2 Producer 1 P000 2 Producer 1 P001 2 Consumer 2 QC 津島博士のパフォーマンス講座 第39回 https://blogs.oracle.com/otnjp/tsushima-hakushi-39 外部表T3側 内部表T1側 スキューの回避を確認 PX BLOCK ITERATOR PX RECEIVE= PX SEND HYBRID HASH PX RECEIVE= PX SEND HYBRID HASH (SKEW) PX BLOCK ITERATOR
  32. GROUP BY PUSH DOWN(GPD) 36 Copyright © 2026, Oracle and/or

    its affiliates GROUP BYを早い段階で部分集計し、PXセット間に流すデータ量を削減する仕組み • 部分集計と最終集計の2段階でGROUP BYが発生するコストと、PXセット間のデータ量が削減されるコストを オプテイマイザが比較して自動決定 • ユニーク度が高くGROUP BYの結果、結果件数があまり減らない集計処理には、GPDは不向き これもオプティマイザが判断 • RACのインターノード・パラレル実行の場合、通信量削減はさらに効果的 • 1PXあたりに求められる最大PGA量を低くする効果もあり • DISTINCTではGPDが発生しないので、GROUP BYに書き換えることで高速化することがある
  33. GROUP BY PUSH DOWN 37 Copyright © 2026, Oracle and/or

    its affiliates GROUP BY PUSH DOWNの有無の比較 SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id ------------------------------------------------------------------------- | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 7 | TABLE ACCESS FULL| SALES | Q1,00 | PCWP | | ------------------------------------------------------------------------- GROUP BY PUSH DOWNなしの場合 GROUP BY PUSH DOWNありの場合 SELECT prod_id,SUM(amount_sold) FROM sales GROUP BY prod_id -------------------------------------------------------------------------- | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | Q1,01 | PCWP | | | 4 | PX RECEIVE | | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH | | 6 | HASH GROUP BY | | Q1,00 | PCWP | | | 7 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | | 8 | TABLE ACCESS FULL| SALES | Q1,00 | PCWP | | -------------------------------------------------------------------------- PX SEND HASHの前に部分集計を実施して、 PX間通信に必要なデータ量を削減 PX RECEIVE PX RECEIVE
  34. パーティション・ワイズ結合 38 Copyright © 2026, Oracle and/or its affiliates 最初からパラレル結合可能な形で分割されているため、再分配するPX間送信が必要ない

    2個の表が両方とも結合キーでパーティション化されている場合 SELECT s.prod_id, c.unit_price FROM sales s, costs c WHERE s.prod_id = c.prod_id AND s.time_id = c.time_id AND s.promo_id = c.promo_id AND s.channel_id = c.channel_id AND s.amount_sold >= 1000 AND c.unit_price >= 1000 -------------------------------------------------------------------------- | Id | Operation | Name | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | 1 | PX COORDINATOR | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10000 | Q1,00 | P->S | QC (RAND) | | 3 | PX PARTITION RANGE ALL| | Q1,00 | PCWC | | |* 4 | HASH JOIN | | Q1,00 | PCWP | | |* 5 | TABLE ACCESS FULL | COSTS | Q1,00 | PCWP | | |* 6 | TABLE ACCESS FULL | SALES | Q1,00 | PCWP | | --------------------------------------------------------------------------- PXセットがひとつだけ、つまり PXセット間の通信が発生していない
  35. まとめ 40 Copyright © 2026, Oracle and/or its affiliates 1.

    SQLのパラレル実行のイメージをつかむ ・イントラ・オペレーション並列化とインターオペレーション並列化 ・パラレル実行の動作イメージを実行計画からつかむ 2. パラレル実行の課題1:データ・スキュー ・ 結合(HASH JOIN)でのPX SEND HASHのスキュー発生 ・ BROADCASTおよびSmall Table Replicateによる解決 ・ SQLのホット・キー分離書換えによる解決 3. パラレル実行の課題2:パラレル間データ通信 ・ 誤って大きい表をBROADCASTする問題 ・ PQ SEND HYBRID HASHによる解決 PQ SEND HYBRID HASH(SKEW) ・ GROUP BY PUSH DOWN ・ パーティション・ワイズ結合
  36. 参考情報 41 Copyright © 2026, Oracle and/or its affiliates 特に参考にしたもの★をつけています

    マニュアル:VLDBおよびパーティショニング・ガイド • https://docs.oracle.com/cd/E82638_01/vldbg/using-parallel.html ホワイトペーパー:Oracle Databaseでのパラレル実行 • https://www.oracle.com/technetwork/jp/database/bi-datawarehousing/twp-parallel-execution-fundamentals- 133639-ja.pdf ★津島博士のパフォーマンス講座 第20回,第39回 • https://blogs.oracle.com/otnjp/tsushima-hakushi-20 • https://blogs.oracle.com/otnjp/tsushima-hakushi-39 Oracle Database Technology Night #48 津島博士のパフォーマンス講座 - SQLチューニングは実行計画から Oracle Database Technology Night #48 津島博士のパフォーマンス講座 - SQLチューニングは実行計画から (Q&A) • https://speakerdeck.com/oracle4engineer/oracle-database-technology-night-number-48-jin-dao-bo-shi- falsepahuomansujiang-zuo-sqltiyuninguhashi-xing-ji-hua-kara • https://speakerdeck.com/oracle4engineer/oracle-database-technology-night-number-48-jin-dao-bo-shi- falsepahuomansujiang-zuo-sqltiyuninguhashi-xing-ji-hua-kara-q-and-a ★シバタツ流! パラレル・クエリーの徹底活用とチューニングの極意 • https://www.oracle.com/webfolder/technetwork/jp/ondemand/ddd2013/A-4.pdf