<<追記スタート>>
前提と何を訴えたいかを書いていなかったので追加します。
あと、BLOG慣れっていうか文章の書き方、書かなきゃいけないことなど
私自身がわかっていない部分もあり、
不備があるかもしれませんが、その場合はコメントに書いて指摘していただけたら
嬉しいです。
(それで書き方の勉強もしたいと思っています)
(訴えたいこと)
SQLServerにはTopというものが存在し、結果に対し頭からn件を取得することが出来ます。
SQL_Server2005からROW_NUMBERの関数が使えるようになり、
単純にROW_NUMBERで振った行番号のx~y件という指定でページ指定などすることはありますが、
そのためにTopの存在価値が見えにくくなっているのではないかという思いが 私にはあります。
なので、Topの良さを結果として見せてみたいなぁ・・・・ってだけなんです。
#BLOGなれしていないし、説明下手なんで通じにくいかも知れません。ごめんなさい。
(前提)
とりあえず基本的に1ページ目から2,3,4・・・という風にページは順方向で進むことだけにしました。
(逆も考えるとまた複雑になり、本来の目的を失いそうだったので(^^; )
1ページ目に表示した最後の行にあるデータはどこかに保持しておけるものとします。
(Webならセッションに入れたりとか、画面に隠し項目として格納しておいて、Postされてくるとか
まぁ、手はたくさんありそうな気がします。)
<<追記エンド>>
SQLServer2005からROW_NUMBER関数が追加されたので、
Oracleに慣れ親しんだ方などは、(rownumやROW_NUMBERと同じ感覚で)
この関数を使用して「x~y件目」をWHERE句で指定することで対応されるかもしれません。
が、ROW_NUMBERはSELECT句で使用できるため、
x~yの範囲をBETWEENなどで指定する際、
一度サブクエリにして行番号を確定させないといけません。
#以下出てくるSQLは
#SQLServer2005にIDとVALUEの列があり、IDにインデクスを張ったTESTテーブルを作成し、
#行数を16,777,217にして実行しています。
<SQLパターン1>
-------------------------------------------------------------------
SELECT
id , value
FROM
(
SELECT
id, ROW_NUMBER() OVER ( ORDER BY id) RN, value
FROM test
) t
WHERE
RN BETWEEN x AND y
-------------------------------------------------------------------
# ROW_NUMBERで行番号を振り(RN列になります)
#その列に対しBETWEENでx~yを指定するSQLになります。
この操作はちょっとコスト高いです。
#私の実験状態ではクエリコスト35%でした。
これをSQLServerのTop nを使用して少し改良してみます。
<SQLパターン2>
-------------------------------------------------------------------
SELECT Top 10
id , value
FROM
(
SELECT
id, ROW_NUMBER() OVER ( ORDER BY id) RN, value
FROM test
) t
WHERE
RN >= x
ORDER BY id
-------------------------------------------------------------------
WHEREにあったBETWEENをはずし、TOP 10と指定することで、
x以上の行番号を持つデータで最初の10件を取得するというSQLです。
この操作はパターン1より少しコストダウンしているようです。
#私の実験状態ではクエリコスト33%でした。
最後にテーブルに主キーとなる列があり、その値にてx~y件を取得するパターンで出来ることですが、
ROW_NUMBERを使わず、始まりとなるキー値を指定し、そこから先頭10件を取得するということをやってみます。
<SQLパターン3>
-------------------------------------------------------------------
SELECT Top 10
id , value
FROM
test
WHERE
id > (前回取得時に保持しておいた最大ID)
ORDER BY id
-------------------------------------------------------------------
# (前回取得時に保持しておいた最大ID)の部分は
#1ページ目であれば、その列に格納される最小値。
#2ページ目以降であれば1つ前に取得した時に保持したIDの最大値を指定。
これが一番コスト低く、
私の環境ではクエリコストが32%でした。
テーブルの設計などにより、出来るパターン・出来ないパターンが出てくるとは思いますが、
うまく列の値やROW_NUMBER、TOPを使用して
ご希望のデータを早く取り出せるようになるためのサンプルになれば幸いです。
#上記結果はあくまで私の環境にて出た結果ですので、
#一度ご自分の環境でも試してみてください。
<<再び追記>>
パターン3で逆バージョンを考えてみました。
(3,2,1ページって表示するタイプです。)
そうしたらこんなSQLが出来ちゃいました。
WithクエリだとORDER BYが使えるので、DESCで取得→10件に絞る→IDの昇順に並び替える
って考えてみました。
-------------------------------------------------------------------
WITH SQLTMP AS (
SELECT Top 10
id , value
FROM
Test
WHERE
id < (前回取得時に保持しておいた最小ID)
ORDER BY id desc
)
SELECT * from SQLTMP ORDER BY id
-------------------------------------------------------------------
全体クエリコストが89%って・・・高い(^^;
けど、個々の処理を見てみたら、Sortでコストが78%と出ていて
対象行数が10行なので、実はそんなに負荷高くない?