2022.12.21
SQLチューニング(第41回)「ROWNUMの理解と関連SQL性能問題の理解」(1/6回)
今回から6回シリーズで、「ROWNUMの理解と関連SQL性能問題の理解」と題して、情報をお届けします。それでは、早速始めましょう。
ROWNUMはOracleで提供する仮想カラムで、Select節で使う場合には抽出するデータの順番を付与する用途で使われ、Where節に使う場合には抽出するデータのうち一部データだけ持ってくる用途で使われます。 特にWhere節に使われるROWNUMはインデックスの特性を利用して、部分範囲処理に誘導でき、うまく使えば効率的なSQLになります。
ROWNUMが1回の順番を付与することと、SQLを解釈するときにROWNUMの使用位置とSQLのコンポーネントとの関係を理解すれば、ROWNUMをより効率的に使用することができるでしょう。
これから、基本的なROWNUMに対する内容を調べていきましょう。
12.1 ROWNUMデータを先に抽出した後、問い合わせよう
ROWNUM_T1テーブルには下記のように合計10件のデータがあります。
C1 C2 C3
----- -- ---------
1 C 101
2 D 102
3 E 103
4 F 104
5 G 105
6 H 106
7 I 107
8 J 108
9 K 109
10 L 110
10件のデータに対して下記のようにSQLを実行してみましょう。
テーブル12-1. ROWNUMのデータ抽出
SQL[1] | SQL[2] | ||
SELECT * FROM (SELECT * FROM t1 ORDER BY c1) WHERE ROWNUM >= 1 AND ROWNUM <= 5; | C1 C2 C3 — — —- 1 C 101 2 D 102 3 E 103 4 F 104 5 G 105 | SELECT * FROM (SELECT * FROM t1 ORDER BY c1) WHERE ROWNUM >= 6 AND ROWNUM <= 10; | no rows selected |
SQL[1]とSQL[2]はそれぞれの条件に合うデータが抽出されなければならないと予想されました。 しかしSQL[1]は1 ~ 5まで合計5件のデータが抽出されましたが、SQL[2]は何のデータも抽出されませんでした。
このような結果が導き出された理由は何なのでしょうか?
解答はROWNUMの特性で探してみることで得ることができます。 ROWNUMはSQL結果セットに順番を付与する仮想カラムで、Fetch段階で抽出する最初の行に1を付与します。 そして次の行が抽出されるたびにROWNUMの値を次々と増加させます。 ところで1が存在しないならば、次の順番を付与できないので何のデータも抽出されません。
すなわち、ROWNUMを利用して、ただ一件(ROWNUM=1)のデータだけ抽出したり、1から始めて順にN件のデータを抽出するのは可能ですが、ROWNUMの開始を1でない値から抽出しようとする場合にはデータが抽出されません。
ROWNUMの使用を誤った事例
WHERE ROWNUM = N ( N > 1 )
WHERE ROWNUM > N ( N > 1 )
それならSQL[2]が本来の作成意図のとおりデータを抽出できる方法はないのでしょうか?
ROWNUMが6 ~ 10のデータ(C1値が6 ~ 10)を抽出するためには、次のSQLのように先に抽出対象データにROWNUMを1から順番を付けた後ROWNUMが6 ~ 10までのデータを抽出すれば良いのです。
SELECT c1, c2, c3, RNUM
FROM (
SELECT ROWNUM rnum,
t1.*
FROM (SELECT * FROM t1 ORDER BY c1) T1
)
WHERE rnum >= 6 and rnum <= 10 ;
C1 C2 C3
----- -- ----------
6 H 106
7 I 107
8 J 108
9 K 109
10 L 110
いかがでしたでしょうか?次回は、「ORDER BYとROWNUMを同じ位置に置くのをやめよう」という内容でお送りします。ご期待ください。では、See You ^^
