すべてのプロダクト
Search
ドキュメントセンター

AnalyticDB:ページングキャッシュ (ディープページングクエリのパフォーマンス最適化)

最終更新日:May 14, 2026

AnalyticDB for MySQL は、LIMITOFFSET、および ORDER BY 句を含む大規模なページングクエリを高速化し、ディープページネーションによって引き起こされるパフォーマンスの低下を解決するキャッシュ機能を提供します。このトピックでは、ページングキャッシュ機能を使用してページングクエリのパフォーマンスを最適化する方法と、代替アプローチであるキーセットページネーションについて説明します。

前提条件

V3.2.3 以降の AnalyticDB for MySQL クラスターが作成されていること。

説明
  • AnalyticDB for MySQLのマイナーバージョンを照会するには

  • AnalyticDB For MySQL Data Warehouse Editionクラスターのマイナーバージョンを表示および更新する方法については、「クラスターのマイナーバージョンの更新」をご参照ください。

概要

ディープページングクエリによって引き起こされるパフォーマンスの問題

E コマースプラットフォームのユーザーは、販売量や総合スコアに基づいて商品を並べ替え、高品質な商品を優先的に表示したいと考えます。ほとんどの場合、アプリケーションはページネーション方式を使用して結果を表示し、ページの応答を高速化し、一度に大量のデータを読み込むことによるパフォーマンスの問題を防ぎます。

データベースにおける一般的な方法は、列に基づいてデータを並べ替え、LIMIT 句と OFFSET 句を使用してページングクエリを実行することです。LIMIT 句はページごとに表示されるデータエントリの数を指定し、OFFSET 句はページごとのデータの開始オフセットを指定します。たとえば、ページごとに 100 件のデータエントリを表示したい場合、最初のページのデータをクエリするには次のステートメントを実行します: SELECT * FROM t_order ORDER BY id LIMIT 0, 100。10,001 ページ目のデータをクエリするには、次のステートメントを実行します: SELECT * FROM t_order ORDER BY id LIMIT 1000000, 100

大量のデータに対してページングクエリを実行する場合、深いページングクエリは、グローバルソートと頻繁なルックアップ操作のオーバーヘッドにより、データベースのパフォーマンスを大幅に低下させる可能性があります。この問題は AnalyticDB for MySQL ではより複雑になります。異なるノード間でシャッフルされるデータ量を削減するために、各ストレージノードは topN 計算を実行し、Gather ノードがすべてのストレージノードの実行結果を集約して最終的な結果セットを取得します。

image

最終的な結果セットが正しいことを保証するために、システムは書き換えられた SQL ステートメントを各ストレージノードに割り当てて実行する必要があります。たとえば、10,001 ページ目のデータエントリをクエリする場合、各ストレージノードは次の SQL ステートメントを受け取ります: SELECT * FROM t_order ORDER BY id LIMIT 0, 1000100。その結果、Gather ノードは 100 件のエントリを取得するために、1,000,100 × ストレージノード数 のデータエントリをソートする必要があります。

ソートされるデータ量はページネーションの深さに応じて線形に増加し、パフォーマンスは急激に低下します。これはメモリと CPU リソースに大きな負担をかけ、メモリ不足 (OOM) エラーのリスクを高めます。これがディープページングクエリによって引き起こされるパフォーマンスの問題です。

重要

AnalyticDB for MySQL Enterprise Edition クラスターでは、データは複数のストレージノードに分散されます。ページングクエリにはノード間のデータシャッフルとグローバルソートが必要であり、これによりディープページネーションのパフォーマンスオーバーヘッドはシングルノードデータベースと比較してさらに増幅されます。AnalyticDB for MySQL Basic Edition クラスターはシングルノードアーキテクチャを使用します。Basic Edition クラスターにおけるディープページネーションの問題は、従来のシングルノードデータベースの問題と類似しています。

深いページングクエリによって引き起こされるパフォーマンスの問題を解決するため、AnalyticDB for MySQL はページングキャッシュ機能を提供します。ページングクエリを初めて開始すると、システムはデータベースからデータをクエリし、クエリ結果を一時キャッシュテーブルに保存します。同じ SQL パターンを共有する後続のページングクエリでは、システムが一時キャッシュテーブルからデータを読み取ることで、繰り返し行われるソート操作を防ぎます。これにより、深いページングクエリによるパフォーマンスの問題が効果的に解決され、ORDER BY 句が原因で発生する OOM エラーも防止されます。AnalyticDB for MySQL は、リソースを適切に利用するため、削除ポリシーに基づいて不要になったキャッシュデータを自動的にクリアします。

ページングキャッシュ機能は、次のシナリオに適しています。

  • 大量データの書き出し

    大量のデータを書き出す際、クライアントが不安定になることがあります。この場合、システムはページングクエリを実行して結果をバッチで取得します。LIMIT 句と OFFSET 句を使用する場合、分散環境ではデータが特定の順序で処理されることは保証されません。同じページのデータに対する各クエリは、異なる結果を返す可能性があります。この場合、データの重複や欠落を防ぐために ORDER BY 句を使用する必要があります。ページングキャッシュ機能を使用すると、不要な ORDER BY 句を排除できます。これにより、クエリのパフォーマンスが大幅に向上し、OOM エラーのリスクが減少します。

  • 全データのページングクエリ

    クエリ結果全体は、AnalyticDB for MySQLのホットストレージ領域にキャッシュされます。これにより、データ可用性が保証され、クエリ速度が大幅に向上します。ページングキャッシュ機能を使用して、ページ単位で情報を取得して表示できます。

  • ビジネスレポートの同時実行制御

    同じレポートに対して複数のクエリが同時に開始されると、独立したリクエストがクラスターへの負荷を増大させ、データの不整合を引き起こす可能性があります。ページングキャッシュ機能を使用すると、時間枠内で単一のクエリを実行して、クエリのパフォーマンスとクラスターの安定性を向上させることができます。

使用方法

キャッシュデータベースの設定

ページングキャッシュ機能を使用してクエリ結果をキャッシュする前に、ページングクエリ用の一時キャッシュテーブルを格納するデータベースを指定することを推奨します。データベースを指定しない場合、一時キャッシュテーブルは接続されている内部データベースに格納されます。ページングキャッシュ機能を有効にすると、一時キャッシュテーブルが自動的に作成されます。

説明

外部データベースをキャッシュデータベースとして指定することはできません。

たとえば、paging_cache データベースをキャッシュデータベースとして指定できます。他のデータベースを指定することもできます。

SET ADB_CONFIG PAGING_CACHE_SCHEMA=paging_cache;

ページングクエリに対するページングキャッシュ機能の有効化

複数のページングクエリが同じ SQL パターンを共有する場合、SQL ステートメントにヒントを追加してパフォーマンスを向上させることができます。ヒントを含むページングクエリを初めて開始すると、システムはページングクエリの結果を格納するための一時キャッシュテーブルを作成します。同じ SQL パターンを共有する後続のページングクエリを開始する際に、同じヒントを SQL ステートメントに追加できます。これにより、システムはデータベースへの繰り返しアクセスを必要とせず、一時キャッシュテーブルからデータを読み取ります。

制限事項

LIMIT 句と OFFSET 句を削除した後、ページングクエリを実行したいデータエントリの数は 1 億未満でなければなりません。

説明

クエリ対象のデータエントリ数が 1 億を超える場合は、 チケットを起票 してデータエントリ数の上限を調整してください。

ページングキャッシュ機能を有効化する方法

次のいずれかのヒントを使用して、ページングキャッシュ機能を有効にできます。

  • paging_id=<paging_id>

    paging_id パラメーターは、同じ SQL パターンを共有するが LIMIT 句と OFFSET 句の値が異なる一連のページングクエリに対して作成されるキャッシュテーブルを指定します。クライアントは、一連のページングクエリのキャッシュテーブルを一意に識別するために、一意の ID を生成する必要があります。

    • 指定された paging_id パラメーターが存在しない場合、キャッシュテーブルが作成されます。

    • クエリで指定された paging_id パラメーターが存在し、クエリに含まれる SQL パターンが paging_id パラメーターに対応する SQL パターンと一致する場合、クエリはキャッシュにヒットします。

    • クエリで指定された paging_id パラメーターが存在するが、クエリに含まれる SQL パターンが paging_id パラメーターに対応する SQL パターンと一致しない場合、エラーが発生します。paging_id パラメーターがすでに使用されているかどうかを確認できます。詳細については、本トピックの「キャッシュテーブルに関する情報のクエリ」セクションをご参照ください。

    説明

    paging_id パラメーターは、次の命名規則を満たす必要があります:パラメーター名は 1~127 文字の長さで、文字、数字、アンダースコア (_) を使用できます。パラメーター名は文字またはアンダースコア (_) で始まる必要があります。パラメーター名には、シングルクォーテーション (')、ダブルクォーテーション (")、感嘆符 (!)、またはスペースを含めることはできません。パラメーター名を SQL の 予約語 にすることはできません。

    たとえば、ページングキャッシュ機能を使用する一連のページングクエリの結果に対して、ページング ID を paging123 に設定できます。

    /*paging_id=paging123*/ SELECT * FROM t_order ORDER BY id LIMIT 0, 100;
  • paging_cache_enabled=true

    この方法では、ヒントを頻繁に変更する必要はありません。サーバーは LIMIT 句と OFFSET 句を削除した SQL パターンを使用してページング ID を生成し、一連のページングクエリを識別します。

    SQL パターンマッチングへの依存は、この方法の柔軟性を制限します。LIMIT 句と OFFSET 句を除いて同じ SQL パターンを共有するページングクエリに対してキャッシュテーブルが存在しない場合、キャッシュテーブルが作成されます。LIMIT 句と OFFSET 句を除いて同じ SQL パターンを共有するページングクエリに対してキャッシュテーブルが存在する場合、そのキャッシュテーブルがデータのクエリに使用されます。

    ステートメントの例:

    /*paging_cache_enabled=true*/ SELECT * FROM t_order ORDER BY id LIMIT 0, 100;

キャッシュテーブルの作成に失敗した場合は、ページングクエリのキャッシュデータをクリアし、ページングクエリを再実行してキャッシュテーブルを作成する必要があります。

キャッシュテーブルに関する情報のクエリ

現在のクラスター内のすべてのページングクエリのキャッシュテーブルに関する情報 (ページング ID、キャッシュサイズ、キャッシュステータスなど) をクエリできます。

SELECT * FROM INFORMATION_SCHEMA.KEPLER_PAGING_CACHE_STATUS_MERGED;

キャッシュテーブルの最大数の指定

現在のクラスター内のキャッシュテーブルの最大数を指定できます。デフォルト値: 32。

SET ADB_CONFIG PAGING_CACHE_MAX_TABLE_COUNT=32;

キャッシュテーブルの総数が上限を超えているときにキャッシュテーブルを作成しようとすると、エラーが発生します。エラーメッセージの例:

Paging cache count exceeds the limit. Please clean up unused caches or increase the related parameter using SET ADB_CONFIG PAGING_CACHE_MAX_TABLE_COUNT=xxx.

エラーメッセージに基づいて、不要になったキャッシュデータをクリアするか、キャッシュテーブルの最大数を増やしてください。

キャッシュテーブルの有効期間の指定

キャッシュテーブルの有効期間を指定できます。単位:秒。有効期間が終了すると、キャッシュテーブルは無効になります。同じ SQL パターンを共有する後続のページングクエリを開始すると、システムはデータベースにアクセスし、キャッシュテーブルを更新します。ほとんどの場合、レポートの同時実行制御シナリオでキャッシュテーブルの有効期間を指定できます。

たとえば、/*paging_cache_enabled=true, paging_cache_validity_interval=300*/ ヒントを使用して、キャッシュテーブルが作成後 300 秒間有効になるように設定できます。ステートメントの例:

/*paging_cache_enabled=true, paging_cache_validity_interval=300*/ SELECT * FROM t_order ORDER BY id LIMIT 0, 100;

ページングクエリのキャッシュデータのクリア

ページングキャッシュ機能を使用してページングされたクエリ結果をキャッシュする場合、キャッシュデータは AnalyticDB for MySQL のホットストレージ領域にキャッシュされます。特定のキャッシュデータが不要になった場合は、キャッシュデータをクリアして、使用可能なストレージを増やすことができます。

手動クリア

  • SQL パターンで指定されたページングクエリのキャッシュデータ

    /*paging_cache_enabled=true, invalidate_paging_cache=true*/ ヒントを使用して、SQL パターンで指定されたページングクエリのキャッシュデータをクリアします。

    ステートメントの例:

    /*paging_cache_enabled=true,invalidate_paging_cache=true*/ SELECT * FROM t_order ORDER BY id LIMIT 0, 100;
  • paging_id パラメーターで指定されたページングクエリのキャッシュデータ

    paging_id パラメーターで指定されたページングクエリのキャッシュデータをクリアします。

    ステートメントの例:

    CLEAN_PAGING_CACHE paging123;
    説明

    paging_id パラメーターの値を取得する方法については、本トピックの「キャッシュテーブルに関する情報のクエリ」セクションをご参照ください。

自動クリア

キャッシュの有効期限を指定して、指定された時間範囲内にアクセスされなかったページングクエリのキャッシュデータをクリアできます。デフォルト値: 3600。単位:秒。デフォルトでは、1 時間以内にアクセスされなかったキャッシュデータは自動的にクリアされます。

SET ADB_CONFIG PAGING_CACHE_EXPIRATION_TIME=3600;

代替策:キーセットページネーション

ビジネスシナリオがカーソルベースのナビゲーション (たとえば、任意のページにジャンプするのではなく、次のページや前のページに移動する) をサポートしている場合、従来の OFFSET ベースのページネーションの代替としてキーセットページネーションを使用できます。OFFSET を使用して行をスキップする代わりに、キーセットページネーションは WHERE 句を使用して、最後に取得した値に基づいて行をフィルター処理します。これにより、ディープページにおけるグローバルソートとノード間のデータシャッフルのオーバーヘッドを回避できます。

たとえば、id 列が主キーであり、現在のページの最後の id の値が 1000 であると仮定します。次の SQL ステートメントを使用して、次のページをクエリします。

-- 従来のディープページネーション (低速)
SELECT * FROM t_order ORDER BY id LIMIT 1000, 100;

-- キーセットページネーション (高速、推奨)
SELECT * FROM t_order WHERE id > 1000 ORDER BY id LIMIT 100;

キーセットページネーション方式では、多数の行をソートしたりスキップしたりすることなく、インデックスから直接次の行のバッチのみを取得します。これにより、ディープページネーションによって引き起こされるパフォーマンスの低下が解消されます。クエリのパフォーマンスは、ページネーションの深さに関係なく一定に保たれます。

一般的なエラーとトラブルシューティング

Paging cache prepare failed, and cache is not available

エラーメッセージ:

Paging cache prepare failed, and cache is not available. Please use /*paging_cache_enabled=true,invalidate_paging_cache=true*/ to clean the unavailable cache or set a specific pagingId with /*paging_id=xxx*/ to gen a new cache. Note that the old and new cache data may be inconsistent.

原因:ページングキャッシュ機能を使用してデータをクエリする際、ノードの再起動やスケーリングなどの例外が発生することがあります。ページングクエリが作成に失敗したキャッシュテーブルにヒットした場合、サーバーはデータベースにアクセスせず、キャッシュテーブルを自動的に再作成しません。サーバーはエラーをスローします。

解決策:データの整合性を確保するために、次の操作を実行することを推奨します。データ書き出しシナリオでは、書き出したデータと利用できないキャッシュデータをクリアしてから、ページングクエリを再実行してキャッシュテーブルを再作成することを推奨します。他のシナリオでは、利用できないキャッシュデータをクリアするか、paging_id パラメーターに新しい値を指定してから、ページングクエリを再実行してキャッシュテーブルを再作成することを推奨します。

パフォーマンス比較

100 GB の TPC-H データセットを使用して、データ書き出しシナリオにおけるページングクエリに対するページングキャッシュ機能の最適化効果を評価します。

このテストでは、100 万エントリの書き出しデータが含まれます。各ページには 10 万エントリが含まれます。次のステートメントを実行して、最初のページに対してページングクエリを実行します。

-- ページングキャッシュ機能を使用しない一般的なページングクエリ
SELECT * FROM lineitem ORDER BY l_orderkey,l_linenumber LIMIT 0,100000;

-- ページングキャッシュ機能を使用したページングクエリ (データ書き出しシナリオでは ORDER BY を削除)
/*paging_cache_enabled=true*/ SELECT * FROM lineitem LIMIT 0,100000;

テスト結果:

クエリリクエストは単一同時実行モードで実行されます。データ書き出しプロセス中、一般的なページングクエリの平均応答時間は 54,391 ms です。ページングキャッシュ機能を有効にすると、平均応答時間は 525 ms になります。パフォーマンスは約 103 倍向上します。CPU 使用率とメモリ使用量は大幅に減少します。

ページングキャッシュ機能は、データ書き出しプロセス中のページングクエリの応答時間を大幅に短縮し、CPU およびメモリリソースの消費を効果的に削減します。

image.png