一番上のoffset
を見つける必要があるため、時間がかかります 行をスキャンし、次の100をスキャンします。巨大なオフセットを処理している場合、最適化の量によってそれが変わることはありません。
これは、クエリが文字通り指示するためです。 offset 3900000
を使用して多数の行にアクセスするDBエンジン -これは390万行です。これをいくらかスピードアップするオプションは多くありません。
超高速RAM、SSDなどが役立ちます。しかし、そうすることで得られるのは一定の要因だけです。つまり、十分に大きなオフセットに到達するまで、缶を蹴り飛ばすだけです。
テーブルがメモリに収まるようにするために、余裕を持って、初回を除いて、より大きな定数係数で同様に役立ちます。ただし、これは十分な大きさのテーブルまたはインデックスでは不可能な場合があります。
インデックスのみのスキャンを実行していることを確認すると、ある程度は機能します。 (velisの回答を参照してください。多くのメリットがあります。)ここでの問題は、すべての実用的な目的で、インデックスをディスクの場所とインデックス付きフィールドを格納するテーブルと見なすことができることです。 (それよりも最適化されていますが、妥当な最初の近似です。)十分な行がある場合でも、十分に大きいオフセットで問題が発生します。
行の正確な位置を保存して維持しようとすることも、コストのかかるアプローチになるはずです(これは、たとえばbenjistによって提案されています)。技術的には実行可能ですが、ツリー構造でMPTTを使用する場合と同様の制限があります。読み取りは大幅に増加しますが、ノードが挿入、更新、または削除されると、データの大部分を同時に更新する必要があるため、書き込み時間が長くなります。
うまくいけばもっと明確になるように、これほど大きなオフセットを扱っているときは、本当の魔法の弾丸はありません。多くの場合、別のアプローチを検討することをお勧めします。
ID(または日付フィールド、またはその他のインデックス可能なフィールドのセット)に基づいてページをページ付けする場合、潜在的なトリック(たとえば、blogspotで使用される)は、クエリをインデックスの任意のポイントから開始させることです。
別の言い方をすれば、次の代わりに:
example.com?page_number=[huge]
次のようなことをします:
example.com?page_following=[huge]
そうすることで、インデックス内のどこにいるかを追跡でき、膨大な数の行を調べなくても正しい開始点に直接進むことができるため、クエリは非常に高速になります。
select * from foo where ID > [huge] order by ID limit 100
当然、あなたは例えばにジャンプする能力を失います。 3000ページ。しかし、これを正直に考えてみてください。毎月のアーカイブに直接アクセスしたり、検索ボックスを使用したりする代わりに、サイトの膨大なページ数に最後にジャンプしたのはいつですか。
ページ付けをしているが、何らかの方法でページオフセットを維持したい場合は、さらに別のアプローチとして、より大きなページ番号の使用を禁止することもできます。それはばかげているわけではありません:それはグーグルが検索結果で行っていることです。検索クエリを実行すると、Googleは結果の推定数を提供します(explain
を使用して妥当な数を取得できます )、そしてあなたが上位数千の結果を閲覧することを可能にします-それ以上は何もありません。とりわけ、パフォーマンス上の理由からそうします。まさにあなたが遭遇している理由です。