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

AnalyticDB:ページングキャッシュ (ディープページネーションの最適化)

最終更新日:Apr 11, 2026

AnalyticDB for MySQL のページングキャッシュ機能は、キャッシュ機構を利用して、LIMITOFFSETORDER BY を使用する大規模なページングクエリの効率を向上させ、ディープページネーションのパフォーマンス問題とリソースのボトルネックを解決します。このトピックでは、ページングクエリでページングキャッシュ機能を使用する方法について説明します。

前提条件

ご利用のクラスターのマイナーバージョンが 3.2.3 以降である必要があります。

説明

マイナーバージョンを確認および更新するには、AnalyticDB for MySQL コンソールクラスター情報 ページにある構成情報 セクションに移動します。

ページングキャッシュとは

ディープページネーションがパフォーマンス問題を引き起こす理由

E コマースプラットフォームでは、ユーザーはしばしば販売量や総合評価で商品を並べ替え、高品質な商品を優先的に表示します。ページの応答速度を向上させ、一度に大量のデータを読み込むことによるパフォーマンス問題を回避するため、アプリケーションは通常、ページネーションを使用して結果を表示します。

データベースでは、ページネーションの一般的な方法は、特定の列でソートし、LIMITOFFSET を使用することです。LIMIT はページあたりの行数を指定し、OFFSET は開始オフセットを指定します。たとえば、1ページあたり 100件のレコードを表示する場合、最初のページをクエリする SQL ステートメントは SELECT * FROM t_order ORDER BY id LIMIT 0, 100 となります。より深いページ、たとえば 10,001 ページ目 (最初の 1,000,000 件のレコードをスキップ) の場合、SQL ステートメントは SELECT * FROM t_order ORDER BY id LIMIT 1000000, 100 となります。

大規模なデータセットで深いページをクエリすると、グローバルソートと頻繁なテーブルルックアップのオーバーヘッドにより、データベースのパフォーマンスが急激に低下する可能性があります。この問題は、AnalyticDB for MySQL のような分散データウェアハウスではさらに複雑になります。ノード間のデータシャッフル量を減らすため、各ストレージノードはまずローカルで Top-N 計算を実行します。その後、単一のストレージノードが各ストレージノードからの結果を集約してソートし、最終的な結果セットを返します。

最終結果の正確性を保証するため、書き換えられた SQL ステートメントは各ストレージノードに送信される必要があります。たとえば、10,001 ページ目をクエリする場合、各ストレージノードは SELECT * FROM t_order ORDER BY id LIMIT 0, 1000100 というクエリを受け取ります。必要なのは 100 行だけですが、単一のノードは 1,000,100 * (ストレージノード数) 行に対してグローバルソートを実行する必要があります。

ソート対象のデータ量はページネーションの深さに比例して増加し、パフォーマンスが急激に低下します。これにより、メモリと CPU リソースに大きな負荷がかかり、メモリ不足 (OOM) エラーのリスクが高まり、「ディープページネーション」問題につながります。

ページングキャッシュは、AnalyticDB for MySQL におけるディープページネーションのパフォーマンスを最適化するためのキャッシュ戦略です。初めてページングクエリを実行すると、システムはデータベースからデータを取得し、結果を一時テーブルに保存します。その後のベースクエリ (LIMITOFFSET パラメーター以外は元のクエリと同一) は、キャッシュテーブルから直接読み取ることができます。このプロセスにより、繰り返し行われるソート操作が回避されます。これにより、ディープページネーションクエリのパフォーマンス問題が効果的に解決されるだけでなく、ORDER BY によって引き起こされるメモリ不足 (OOM) エラーも防止されます。さらに、AnalyticDB for MySQL は、立ち退きポリシーに基づいて未使用のページングキャッシュを自動的にクリアし、効率的なリソース利用を保証します。

この機能は、以下のシナリオに適用されます。

  • 大規模なデータエクスポート

    大量のデータをエクスポートする際、一度に多くのデータをフェッチするとクライアントが不安定になることがあります。これを防ぐため、ページングクエリを使用して結果をバッチでフェッチできます。しかし、分散環境では、LIMITOFFSET を使用しても、データが決定的な順序で処理されるとは限りません。これにより、同じページがクエリごとに異なる結果を返す可能性があります。したがって、エクスポート中にデータが重複したり欠落したりしないように、明示的に ORDER BY 句を追加する必要があります。ページングキャッシュを使用することで、ビジネスロジックで ORDER BY 句が不要な場合は削除できます。これにより、クエリのパフォーマンスが大幅に向上し、メモリ不足 (OOM) エラーのリスクが大幅に減少します。

  • 完全なデータセットのページングクエリ

    クエリの完全な結果セットは AnalyticDB for MySQL のホットストレージにキャッシュされ、データが即座に利用可能になり、クエリ速度が大幅に向上します。ページネーションを通じて必要な情報を迅速に取得し、表示できます。

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

    複数のユーザーが同じレポートを同時にクエリする場合、各リクエストは通常、独立したクエリをトリガーします。これにより、クラスターの負荷が増加し、データ整合性の問題が発生する可能性があります。ページングキャッシュを使用すると、これらのリクエストを特定のタイムウィンドウ内で単一のグローバルクエリに統合でき、クエリのパフォーマンスとクラスターの安定性が大幅に向上します。

使用方法

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

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

説明

キャッシュデータベースは外部データベースにはできません。

次の例では、データベース `paging_cache` をキャッシュデータベースとして指定します。他の任意のデータベースを指定することもできます。

SET ADB_CONFIG PAGING_CACHE_SCHEMA=paging_cache;

ページングクエリでのページングキャッシュの有効化

クエリ文にヒントを追加してページングキャッシュを有効にし、ページングクエリのパフォーマンスを向上させます。ヒント付きで初めてページングクエリを開始すると、ページングクエリの結果を保存するための一時テーブルが作成されます。その後のベースクエリでは、同じヒントをクエリ文に追加することで、再度データベースにアクセスすることなく、キャッシュテーブルから直接データを読み取ることができます。

制限事項

LIMITOFFSET 句を削除した場合、ページングクエリが返すデータ行数は 1 億行未満でなければなりません。

説明

クエリ対象の行数が 1 億行を超える場合は、チケットを起票してテクニカルサポートに連絡し、行数制限の引き上げを依頼してください。

方法

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

  • paging_id=<paging_id>

    paging_id パラメーターは、関連するページングクエリのグループを識別するために使用されます。クライアントは、ページングクエリのグループのキャッシュを一意に識別するために、一意の ID を生成する必要があります。

    • 指定された paging_id が存在しない場合、キャッシュが生成されます。

    • クエリは、その paging_id が存在し、現在のクエリがキャッシュ内のベースクエリと一致する場合にキャッシュにヒットします。

    • 指定された paging_id が存在するが、現在のクエリがキャッシュ内のベースクエリと一致しない場合は、エラーが発生します。paging_id がすでに使用されているかどうかは、既存のキャッシュをクエリすることで確認できます。

    説明

    paging_id は、英字またはアンダースコア (_) で始まり、英字、数字、アンダースコア (_) のみを含み、長さは 1~127 文字である必要があります。引用符、感嘆符 (!)、スペースを含めることはできず、SQL の予約語にすることはできません。

    次の例は、paging123 がページングキャッシュ機能を使用するページングクエリの結果の ID であることを示しています。

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

    この方法では、頻繁にヒントを変更する必要はありません。サーバーは自動的にクエリ文から LIMITOFFSET 句を削除し、クエリが同じページングクエリグループに属するかどうかを識別するための paging_id を生成します。

    この方法は自動マッチングに依存するため、柔軟性が限られています。ベースクエリのキャッシュが存在しない場合は、新しいキャッシュが作成されます。ベースクエリのキャッシュがすでに存在する場合は、クエリは直接キャッシュにアクセスします。

    例:

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

キャッシュの作成に失敗した場合は、まずページングクエリキャッシュをクリアしてから、ページングクエリを再開して新しいキャッシュデータを生成する必要があります。

既存のキャッシュのクエリ

現在のクラスター内のすべてのページングキャッシュに関する情報を取得します。これには、paging_id、キャッシュサイズ、キャッシュステータスなどが含まれますが、これらに限定されません。

SELECT * FROM INFORMATION_SCHEMA.KEPLER_PAGING_CACHE_STATUS_MERGED;

キャッシュの最大数の設定

キャッシュの最大数です。デフォルト値は 100 です。

SET ADB_CONFIG PAGING_CACHE_MAX_TABLE_COUNT=100;

制限に達した後に新しいキャッシュを作成しようとすると、システムはエラーを返します。エラーメッセージは次のとおりです。

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.

エラーメッセージの指示に従って、未使用のキャッシュをクリアするか、キャッシュの最大数を増やしてください。

キャッシュの有効期間の設定

キャッシュに有効期間を設定できます。指定した期間が経過すると、キャッシュは期限切れになります。その後のベースクエリは、再度データベースにアクセスしてデータを取得し、キャッシュテーブルを更新します。キャッシュの有効期間は秒 (s) 単位で測定され、通常はレポートシナリオでの同時実行制御に使用されます。

たとえば、paging_cache_validity_interval=300 は、キャッシュが 300 秒間有効であることを示します。これは、キャッシュが生成されてから 300 秒後に期限切れになることを意味します。以下に例を示します。

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

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

ページングキャッシュを使用してページングクエリの結果をキャッシュすると、キャッシュデータは AnalyticDB for MySQL のホットストレージに保存されます。キャッシュが不要になった場合は、それをクリアしてストレージスペースを解放できます。

手動クリーンアップ

  • 指定されたベースクエリのページングクエリキャッシュのクリア

    paging_cache_enabled=true,invalidate_paging_cache=true を設定して、ベースクエリに対応するページングクエリのキャッシュされた結果をクリアします。

    例:

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

    paging_id を指定して、この paging_id で識別されるページングクエリキャッシュを削除します。

    例:

    CLEAN_PAGING_CACHE paging123;
    説明

    paging_id は、既存のキャッシュをクエリすることで取得できます。

自動クリーンアップ

キャッシュの有効期限のしきい値を指定して、指定された期間内にアクセスされていないページングクエリキャッシュを自動的に削除できます。デフォルトの有効期限のしきい値は 600 秒 (s) です。これは、キャッシュが 10 分間アクセスされない場合に自動的にクリアされることを意味します。

SET ADB_CONFIG PAGING_CACHE_EXPIRATION_TIME=600;

ページングキャッシュのグローバルな無効化

ページングキャッシュが無効になると、ページングキャッシュ関連のすべてのヒントが無効になり、ページングクエリは元のクエリパスを使用して処理されます。

SET ADB_CONFIG PAGING_CACHE_ENABLE=false;

ページングキャッシュ機能を無効にした後、SHOW ADB_CONFIG KEY=PAGING_CACHE_ENABLE; コマンドを実行して、設定が有効になっているか確認できます。

トラブルシューティング

ページングキャッシュの準備に失敗

完全なエラーメッセージ:

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 万行のデータをエクスポートし、1ページあたり 10 万行とします。最初のページの SQL は次のとおりです。

-- 標準のページングクエリ、ページングキャッシュ機能を使用しない
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