何年にもわたって、開発者の汗の山が効率的にページング結果セットに入りました。しかし、答えは1つではありません。それは、ユースケースによって異なります。ユースケースの一部はページを効率的に取得することであり、一部は完全な結果セットに含まれる行数を把握することです。ページングに少し迷ってしまったら申し訳ありませんが、この2つは私の心の中でかなり緊密に結合されています。
多くの戦略がありますが、何らかのデータ量があり、ユースケースに適合しない場合、そのほとんどは悪い戦略です。これは完全なリストではありませんが、以下にいくつかのオプションがあります.....
個別に実行Count(*)
- 単純な「MyTableからcount(*)を選択」を実行する別のクエリを実行します
- 小さなテーブルにシンプルで簡単
- 狭いか、使用できるコンパクトな非クラスター化インデックスを持つ、フィルター処理されていない大きなテーブルに適しています
- 複雑な
WHERE/JOIN
があると故障しますWHERE/JOIN
を実行するための基準 2回は高価です。 - 読み取り数が増えるため、ワイドインデックスに分類されます。
ROW_Number() OVER()
を組み合わせる およびCOUNT(1) OVER(PARTITION By 1)
- これは@RBarryYoungによって提案されました。実装が簡単で、非常に柔軟であるという利点があります。
- 欠点は、これがすぐに非常に高価になる可能性がある多くの理由があることです。
- たとえば、現在作業しているDBには、約6000行のMediaテーブルがあります。それは特に広くはなく、整数のクラスター化されたPKと、コンパクトな一意のインデックスを備えています。それでも、TotalRowsとしての単純な
COUNT(*) OVER(PARTITION BY 1) as TotalRows
結果として約12,000回の読み取りが行われます。これを単純なSELECT COUNT(*) FROM Media
と比較してください。 -12回の読み取り。 Wowzers。
一時テーブル/テーブル変数
- 結果セットを取得し、関連するキーまたは結果のセグメントを一時テーブル/テーブル変数に挿入する戦略はたくさんあります。
- 中小規模の結果セットの場合、これにより優れた結果が得られます。
- このタイプの戦略は、SQLのほぼすべてのプラットフォーム/バージョンで機能します。
- 結果セットを複数回操作することも簡単です(多くの場合、要件です)。
- 欠点は、大規模な結果セットを操作する場合です...一時テーブルに数百万行を挿入するにはコストがかかります。
- 問題を複雑にしているのは、大量のシステムではTempDBに圧力がかかることがかなりの要因になる可能性があり、TempDBでは一時テーブルが効果的に機能していることです。
ガウス和/二重行番号
- このアイデアはサブセットに依存しています 数学者ガウスが理解した何かの(一連の数を合計する方法)。サブセットは、テーブル内の任意のポイントから行数を取得する方法です。
- 一連の数値から(
Row_Number()
)1からNまでの行数は(N + 1) - 1
です。 。リンクの詳細な説明。 - 数式はNだけになるように見えますが、数式に固執すると面白いことが起こり、テーブルの中央のページから行数を計算できます。
- 最終的な結果は、
ROW_Number() OVER(Order by ID)
を実行することです。 およびROW_Number() OVER(Order by ID DESC)
次に、2つの数値を合計し、1を引きます。 - 例としてメディアテーブルを使用すると、読み取りが12,000から約75に減少しました。
- 大きなページでは、データを何度も繰り返すことになりますが、読み取りのオフセットはそれだけの価値があるかもしれません。
- これはあまり多くのシナリオでテストしていないため、他のシナリオでは機能しなくなる可能性があります。
トップ(@n)/行数の設定
- これらはそれ自体が特定の戦略ではありませんが、クエリオプティマイザについて知っていることに基づいた最適化です。
- Top(@n)をクリエイティブに使用する[topはSQL 2008の変数にすることができます]、またはSET ROWCOUNTを使用すると、ワーキングセットを減らすことができます...結果セットの中央のページをプルしている場合でも、結果を絞り込むことができます
- これらのアイデアは、クエリオプティマイザの動作のために機能します...サービスパック/ホットフィックスは動作を変更できます(おそらくそうではありません)。
- certianインスタンスでは、SETROWCOUNTは少し正確になる可能性があります
- この戦略は、完全な行数を取得することを考慮しておらず、ページングをより効率的にするだけです
では、開発者は何をすべきでしょうか?
私のいい男を読んで、読んでください。これが私が頼りにしたいくつかの記事です...
- 大規模な結果セットをページングするためのより効率的な方法
- サーバーサイドページングの最適化-パートI
- サーバーサイドページングの最適化-パートII
- ガウス和の説明
- Microsoft SQLServer2005でランク付けされた結果を返す
- ROW_NUMBER()OVERは、大きな結果セットでは十分に高速ではありません
- SQLクエリから最初のNレコードを取得する
- SQLServer2005を使用したサーバー側のページング
- なぜウィンドウ化された集計関数の論理読み取りが非常に高いですか?
お役に立てば幸いです。