【Oracle】ROWNUMはROW_NUMBERの下位互換なのか?前編

【Oracle】ROWNUMはROW_NUMBERの下位互換なのか?前編

Oracleを使い始めた人のつまずきポイントの1つ。
今回は行番号の話です。

前編では表題の疑問に至った経緯を解説。
後編では処理速度などを確認しつつ、優劣や使い分けの答えを出したいと思います。

Oracleの行番号

行番号は主に検索に関わってきます。
例えば、年齢が若い順に10人取得したい、膨大なデータから適当に100件取得したい、
そんな時は行番号の出番です。

「え?TOPとかLIMITとかは使わないの?」
これらはOracleには存在しないのです。
そのため行番号を巧みに使いこなす必要があるというわけです。
そして行番号を振りたい時に便利なものが2つ用意されています。
それが「ROWNUM」と「ROW_NUMBER」です。

「ROWNUM」

正確にはROWNUM擬似列。
検索結果の行に振られている番号で、下記のように使用します。

SELECT *
FROM tableA
WHERE ROWNUM < 11;

これでテーブルtableAから全レコードから適当に10件取ってくることができます。
ちなみに擬似列とは内部的にこっそり作られる列で、
上の例で言うとtableAで特別な用意をしなくても通常のカラムのように使えます。

「ROW_NUMBER」

正確にはROW_NUMBER分析ファンクション。
こちらも連番を振れるものですが、使用する際は並び順を指定する必要があります。
例はこちら。

SELECT columnA, columnB, ROW_NUMBER() OVER(ORDER BY columnA) AS rn
FROM tableA
WHERE rn < 11;

columnAの昇順で10件分を取得できます。
ちなみに分析ファンクションはWINDOW関数とも呼ばれ、
集計した結果をそれぞれの行に返します。
集合関数(MAX、SUMなど)のように行をまとめたりはしないということですね。

ROWNUMよりROW_NUMBERの方が良い?

非常に似ているこの2つですが、
調べていると段々ROW_NUMBERの方が優れているように感じてきます。
というのもROWNUMは癖が強すぎる!
1つ大きな注意点を挙げるなら、
「ROWNUM→ORDER BYの順に作用する」ということです。
つまり、ぐちゃぐちゃにレコードを取得してすぐに行番号が振られるため、
その後ORDER BYで並び替えると行番号はぐちゃぐちゃになります。
また、WHERE句でROWNUMを使う時も注意が必要で、
これらの対処法は公式リファレンスにまとめられています。

ぶっちゃけROWNUMはORDER BYとセットで使うことがほとんどです。
そのため公式リファレンスにあるようなサブクエリによる対処がほぼ必須です。
それならもっと直感的に使えるROW_NUMBERだけ使っていれば良いように思うわけです。
しかもこちらは標準SQLの関数ですので、
覚えておくと他のデータベースを触る時にも役立ちます。

もっと詳細な違いを…

動作の分かりやすさではROW_NUMBERに軍配が上がりそうです。
しかし、どちらも存在し続けている以上、ROWNUMにも強みはあるはずです。

そんな中、実行速度もほぼ変わらないという噂を聞いたので、
実際にoracleDBを用意して試してみましょう。

…試そうと思いましたが、環境構築で手間取ってしまいました。
使用可能なメモリ不足?容量もメモリも余裕はあるはず。う〜ん。

続きは後編で!