MySQL 9.7 Community Editionのリリースにより、ハイパーグラフ・オプティマイザすべてのユーザーに利用可能になりました。これはMySQLにとって重要な機能強化であり、コミュニティでも大きな注目を集めています。その狙いはシンプルで、複数のテーブルを結合する複雑なクエリに対してより優れた実行計画を生成することです。

ただし、多くの新機能と同様に、ひとつの疑問があがります。それは「有効化すれば、それだけで性能は向上するのか?」という問いです。

結論から言えば、答えは「No」です。

本記事では、まずクエリオプティマイザの役割を説明し、従来のMySQLオプティマイザとハイパーグラフ・オプティマイザの違いを解説します。そのうえで、ハイパーグラフ・オプティマイザによって性能が向上する実際の例を紹介するとともに、すべてのワークロードにおいて最適な選択肢にならない理由についても説明します。読み終える頃には、ハイパーグラフ・オプティマイザが効果を発揮しやすいケースと、従来のオプティマイザに任せた方がよいケースを判断できるようになるでしょう。

クエリオプティマイザとは

SQL文を実行するたびに、データベースはそのクエリをどのような手順で実行するかを決定します。正い結果を返す方法は一つではなく、多くの場合、数十から数百、場合によっては数千通りもの実行方法が存在します。

そこで重要になるのがクエリオプティマイザです。

クエリオプティマイザは、利用可能なインデックス、テーブル統計情報、JOIN順序、推定行数などを考慮し、最も効率的な実行計画(Execution Plan)を選択します。目標は単純で、できるだけ少ない処理で正しい結果を返すことです。

単純なクエリでは通常それほど多くの選択肢はありません。しかし、複数のテーブルをJOINするようになると、クエリオプティマイザの役割は極めて重要になります。同じ結果を返す実行計画でも、一方は数ミリ秒で終わり、もう一方は数秒、あるいは数分かかることもあります。そのため、オプティマイザはリレーショナルデータベースの中でも最も重要なコンポーネントの一つとされています。

従来のクエリオプティマイザとハイパーグラフ・オプティマイザの違い

クエリオプティマイザの最も重要な役割の一つが、テーブルをどの順番でJOINするかを決定することです。一見単純に聞こえますが、実際には非常に複雑な問題です。

テーブルが2つなら組み合わせはわずかですが、数が増えるにつれてJOIN順序の候補は急激に増加します。10テーブル以上になると、すべての組み合わせを現実的な時間内で評価することは困難です。
クエリ自体が1秒で終わるのに、実行計画を求めるだけで10秒かかっていては意味がありません。

この問題を解決するため、MySQLの従来のオプティマイザはコストベース最適化とさまざまなヒューリスティックを組み合わせ、探索範囲を絞り込んでいます。すべてのJOIN順序を評価するのではなく、有望な候補だけを調べることで、多くの場合十分に優れた実行計画を得ています。

一方、ハイパーグラフ・オプティマイザは異なるアプローチを採用しています。従来のJOIN順序探索ではなく、クエリをテーブル間の関係を表すグラフ(Hypergraph)としてモデル化します。これにより、明らかに効率の悪い候補を除外しつつ、従来より広い範囲のJOIN順序を探索できます。その結果、従来のオプティマイザでは見つけられなかった実行計画を選択できる可能性があります。

もちろん、万能ではありません。

より多くの候補を評価するため、最適化処理そのものに時間がかかるというトレードオフがあります。
大規模な分析クエリでは、その追加コスト以上の性能向上が期待できますが、単純なクエリではJOIN順序の選択肢が少ないため、実行時間はほとんど変わらず、場合によっては最適化コストが上回ってしまうこともあります。

つまり、ワークロードによっては従来のオプティマイザの方が同等、あるいはそれ以上の性能を示すケースもあります。

ハイパーグラフ・オプティマイザを有効化する

ハイパーグラフ・オプティマイザの良い点のひとつは、いきなりシステム全体で有効化する必要がないことです。MySQLでは用途に応じて複数の有効化方法が用意されており、目的にあった粒度でテストできます。

最も手軽なのは、クエリ単位でオプティマイザヒントを指定する方法です。

SELECT /*+ SET_VAR(optimizer_switch='hypergraph_optimizer=on') */
…

著者自身も、評価する際にはこの方法を推奨しています。なぜなら、変更を1つのSQL文だけに限定できるため、SQLやスキーマ、データはまったく同じ条件のまま、オプティマイザだけを切り替えて実行計画を比較できるからです。

より大きなワークロードで検証したい場合は、セッション単位でも有効化できます。

SET SESSION optimizer_switch='hypergraph_optimizer=on';

あるいは、テストが完了した際に新しいクライアント接続すべてでデフォルトとして Hypergraph を使用したい場合は、グローバルに有効にすることができます。

SET GLOBAL optimizer_switch='hypergraph_optimizer=on';

この記事の例では、インライン・オプティマイザヒントを使用します。これにより、SQL、スキーマ、データが同一に保たれるため、公平な比較が可能になります。変更されるのはオプティマイザのみであるため、ハイパーグラフ・オプティマイザが結果として生成される実行計画に与える影響を、確認しやくすることができます。

クエリ例

基本を確認したところで、ハイパーグラフ・オプティマイザの効果が発揮されるクエリを見てみましょう。

この例では、sales_ordersales_line を中心としたレポート形式のスキーマを利用しており、customerproductseller、および2025年のアーカイブ済み注文データを格納するテーブル(orders)があります。典型的なスタースキーマではありませんが、eコマースや注文管理システムでよく見られるトランザクションワークロードの一例です。さらに重要な点として、これらのテーブル間の関係により、オプティマイザには複数の結合パスが考えられるため、結合順序が全体的なパフォーマンスの重要な要素となります。

図1: ハイパーグラフ・オプティマイザの説明に使用したレポートスキーマの例
現在の売上テーブル、アーカイブ済み注文データ、および補助的なテーブルを組み合わせたもので、オプティマイザが評価できる複数の結合ルートを作成しています。

以下のクエリは、現在の売上動向を要約するとともに、2025年のアーカイブされた注文データと比較するものです。このクエリでは、現在の注文と過去の注文を組み合わせ、複数のテーブル間で結合を行い、日付範囲、注文ステータス、顧客の地域、販売者のステータス、商品カテゴリなど、いくつかの選択条件を適用しています。
これらのテーブルを結合する有効な方法が複数存在するため、これはまさに、従来のオプティマイザでは考慮されない可能性のある代替の実行計画を、ハイパーグラフ・オプティマイザが探索できるタイプのクエリです。

SELECT COUNT(*) AS matched_lines,
   ROUND(SUM(sl.net_amount), 2) AS current_revenue
FROM sales_order so
JOIN sales_line sl ON sl.order_id = so.order_id
JOIN product p ON p.product_id = sl.product_id
JOIN customer c ON c.customer_id = so.customer_id
JOIN seller s ON s.seller_id = so.seller_id
JOIN orders_2025 o25 ON o25.customer_id = c.customer_id
JOIN order_items_2025 i25 ON i25.order_id = o25.order_id
JOIN product p25 ON p25.product_id = i25.product_id
               AND p25.category_id = p.category_id
WHERE so.ordered_at BETWEEN '2026-11-20' AND '2026-11-30'
  AND so.status = 'PAID'
  AND o25.order_date BETWEEN '2025-01-01' AND '2025-12-31'
  AND o25.status = 'PAID'
  AND c.region IN ('US','DE','NO')
  AND s.active = TRUE
  AND p.category_id IN (7,12,19,34)

実行計画を比較する

さて、ここからが興味深い部分です。まったく同じクエリを2回実行したところ、1回目はMySQLの従来のオプティマイザで、2回目はインラインヒントによってハイパーグラフ・オプティマイザを有効にして実行しました。目的は、同じデータに対してより良い処理ルートを見つけられるかどうかを確認することです。完全なJSON出力は、以下のファイルからさ参照できます。ここに示されている実行計画は、EXPLAIN ANALYZE FORMAT=JSON を使用して生成されたもので、オプティマイザが選択した実行計画に加え、実際の実行統計情報も追加されています。

実行計画の結果をダウンロード

従来のオプティマイザ

従来のオプティマイザがどのように動作しているかを確認するため、クエリの前にEXPLAIN ANALYZE FORMAT=JSONを付けて実行します。

EXPLAIN ANALYZE FORMAT=JSON
SELECT COUNT(*) AS matched_lines,…

私はここではJSONを使うのが好ましく、従来の出力形式よりも少し理解しやすく感じます。実行計画自体は同じですが、目を細めて見なければならない場面が少なくなります。

以下の図は、この実行計画を可視化したものです。

Flowchart of a SQL query execution plan showing a nested loop join across eight tables. The plan starts with a filtered scan of orders_2025, performs primary key and index lookups through customer, sales order, seller, sales line, and product tables, then aggregates the final results. Estimated rows decrease from about 5,560 after the initial filter to about 0.082 rows at the final aggregate.
図2: 従来のオプティマイザによる実行計画を可視化

従来の実行計画は、従来のネストされたループ形式に非常に近いものです。まず、o25 テーブルのスキャンから始まり、2025 年の日付範囲内の支払済み注文に絞り込み、その後、1 行のプライマリキー検索を使用して customer テーブルと結合します。そこから、sales_ordersellersales_lineproductorder_items_2025 を経て、最終的に p25 へと処理が進みます。

この実行計画における重要な詳細は次のとおりです:

  • o25 に対するtable scan
  • o25.status =‘PAID’o25.order_date によるfilter
  • customer に対するsingle-row lookup
  • ix_customer を使用した sales_order のindex lookup
  • seller に対するsingle-row lookup
  • ix_order を使った sales_line に対するsingle-row lookup
  • product に対するsingle-row lookup
  • ix_order_id を使用した order_items_2025 に対するindex lookup
  • PRIMARY を使用した p25 に対するsingle-row lookup
  • p25.category_id = p.category_id に対するfilter

この実行計画は目的を果たしますが、全体としてかなり直線的なネストされたループの連鎖のままになっています。クエリの実行には約451ミリ秒かかります。

ハイパーグラフ・オプティマイザ

それでは、まったく同じクエリをもう一度実行してみましょう。ただし、今回は先ほど説明したインライン・オプティマイザ・ヒントを使用して、ハイパーグラフ・オプティマイザを有効にします。

EXPLAIN ANALYZE FORMAT=JSON
SELECT /*+ SET_VAR(optimizer_switch='hypergraph_optimizer=on') */
COUNT(*) AS matched_lines, ...

クエリそのものは変更されていない点に注目してください。唯一の違いは、このクエリに対してのみハイパーグラフ・オプティマイザを使用するようMySQLに指示するインラインヒントです。これにより、唯一の変数がオプティマイザそのものであるため、オプティマイザの挙動を直接比較することができます。

ハイパーグラフ・オプティマイザによる実行計画を確認してみましょう。

Flowchart of a SQL query execution plan using a hash join followed by index lookups. The plan scans filtered orders_2025 and sales_order tables, joins them with a hash join, then performs lookups through seller, customer, sales line, product, and order items before aggregating the results. Estimated rows decrease from 95,000 after the initial filter to approximately 1,756 rows at the final aggregate.
図3: ハイパーグラフ・オプティマイザによる実行計画を可視化

ハイパーグラフ・オプティマイザは、初期段階で異なるアプローチをとっています。単に線形のネストされたループの連鎖に従うのではなく、結合の一方の側からハッシュテーブルを構築し、so.customer_id = o25.customer_id に対して内部ハッシュ結合を使用して、現在の注文ブランチとアーカイブされた注文ブランチを結合します。後続の結合関係に流れるレコード数が減らされていることで、この実行計画が大幅に高速に完了する理由が分かります。

この実行計画で効果的な所は次のとおりです:

  • PRIMARY を使った o25 の index scan
  • ix_date を使った so index scan
  • so.customer_id = o25.customer_id に対する inner hash join
  • seller のsingle-row lookup
  • customer のsingle-row lookup
  • ix_order を使った sales_line のindex lookup
  • product のsingle-row lookup
  • ix_order_id を使った order_items_2025 のindex lookup
  • ix_category を使った p25 のsingle-row covering lookup

ここがこの記事で示す重要な違いです。ハイパーグラフ・オプティマイザは、単にラベルを変えて同じことを行っているだけではありません。初期段階の結合構造を変更しており、約122ミリ秒で処理を完了します。さらに重要なのは、SQL自体に変更を加えることなく、この改善が達成されたことです。2つの実行の違いは、実行プランを選択したオプティマイザのみです。

この例は、ハイパーグラフ・オプティマイザが改善を目的として設計されたワークロードの種類を示しています。どちらのオプティマイザも有効な実行計画を生成しましたが、ハイパーグラフ・オプティマイザは早い段階でハッシュ結合を導入し、結合グラフの一部を再配置することで異なる結合戦略を選択しました。この変更により、全体の実行時間は約451ミリ秒から122ミリ秒に短縮され、ほぼ4倍の性能改善となりました。

元のクエリは決して遅いものではありませんでしたが、処理対象のデータは比較的少ないものでした。トランザクションシステムが拡大し、テーブルに行数が数百万、さらには数十億行にも達するにつれて、実行計画の効率性はますます重要になっていきます。今日は高速で完了するクエリでも、オプティマイザが不要な処理を行っている場合、明日にはボトルネックとなる可能性があります。ハイパーグラフ・オプティマイザは、より効率的な結合処理を見出すことで、基盤となるデータが拡大し続ける中でも、スケーラビリティに優れた実行計画を提供します。

この例から得られる重要なポイントは、ハイパーグラフ・オプティマイザが複雑な結合ワークロードでクエリ実行時間を大幅に削減する実行方法を見つけられる可能性があることです。複数の結合パスや選択条件が存在する場合、オプティマイザに代替プランを探索するためのさらなる自由度を与えることで、大幅なパフォーマンス向上を実現できます。

まとめ

ハイパーグラフ・オプティマイザは、MySQLのクエリオプティマイザにおける重要な進化です。従来のオプティマイザよりも幅広い結合順序の可能性を探索することで、複雑なマルチテーブルクエリに必要な処理量を大幅に削減する実行プランを見出すことができます。この例が示したように、こうした改善により、SQL自体に変更を加えることなく、実行時間を大幅に短縮することが可能です。

とはいえ、ハイパーグラフ・オプティマイザを万能のパフォーマンス向上ツールとして捉えることは避けるべきです。他のコストベースのオプティマイザと同様、このオプティマイザも利用可能な統計情報、推定カーディナリティ、およびクエリの構造に基づいて判断を行います。ワークロードによっては劇的な改善が見られるものもあれば、ほとんど、あるいは全く変化が見られないものもあり、場合によっては従来のオプティマイザを使用した場合よりもパフォーマンスが低下することもあり得ます。

そのため、ハイパーグラフ・オプティマイザの有効化は「すべてのクエリが速くなる」という前提ではなく、測定の機会として捉えるべきです。現実的なデータ量と本番環境に近いワークロードを使用して、最も重要なクエリを評価してください。数千行に対して良好なパフォーマンスを示すクエリでも、数百万行に対して実行された場合、その挙動は大きく異なる可能性があります。

実行計画を比較する際は、推定コストのみに頼るのではなく、可能な限りEXPLAIN ANALYZEを使用してください。推定実行プランはオプティマイザが予測する動作を示すのに対し、EXPLAIN ANALYZEは実行中に実際に何が起きたかを示します。こうした実際の実行統計情報こそが、オプティマイザの判断が成果を上げているかどうかを、はるかに正確に把握するための手がかりとなります。

ハイパーグラフ・オプティマイザは、MySQLのパフォーマンス向上に役立つもう一つの強力なツールであり、複雑な結合関係を解決するための方法をMySQLに提供します。それがお客様のワークロードにとって最適な戦略となるかどうかは、理論ではなく、測定結果によって決まります。代表的なデータを用いてテストを行い、EXPLAIN ANALYZEで検証し、仮定ではなく結果に基づいて、どのオプティマイザが最高のパフォーマンスを発揮するかを判断してください。