ROWID 擬似列

ROWID とは

  • 格納ブロックのアドレスとそのブロック内の行番号までの情報をもつ
  • 同じオブジェクトにおいてユニーク(オブジェクト内で同じ ROWID を持つレコードは存在しない)
  • 単一レコードへの最速のアクセスパスである。(※)
  • アドレスへのポインタ情報のため格納領域を必要としない(0 バイト)
  • 物理 ROWIDの場合、オブジェクトID(OBJECT_ID) が判別できる

という特徴をもつ。

(※) 参考 : ROWID スキャンより高速なアクセスパス

物理 ROWID

物理 ROWID は新規行が作成されると、その先頭のアドレスで管理される。 一度そのアドレスにデータが配置されると削除されるまで ROWID は変わることはない(※1)。

(※1) パーティション表ROW MOVEMENT が ENABLE の場合にはパーティションの移動を伴う更新では ROWID も変更される。 索引構成表 でも データブロックアドレス(DBA) が変動していくが索引構成表の場合には 論理 ROWID が使用される。
また、ALTER TABLE 〜 MOVE や SHRINK 操作によってもデータの物理的な位置が移動するため DBA は変化し ROWID も変化する。
参考: ALTER TABLE MOVE or SHRINK

拡張 ROWID (外部文字 ROWID)

現在の ROWID 擬似列に該当するのはこの形式
拡張 ROWID は文字列に変換すると 18 バイト(※2)。
ROWID は 4つのパート 'OOOOOOFFFBBBBBBRRR' で構成されている。

  • 6 バイトのオブジェクトID(OOOOOO)*1
  • 3 バイトのデータファイル番号(FFF)
  • 6 バイトのブロック番号(BBBBBB)
  • 3 バイトの行番号(RRR)

(※2) 拡張 ROWID の実サイズはほとんどのプラットフォームで 10 バイト( VSIZE 関数でも確認できる):旧形式の 7 バイトもインデックスなどの一部に残っているらしい。(もしかすると、6 バイトの内部 ROWID の誤解かもしれない:未確認)

DBMS_ROWID パッケージには ROWID から、それぞれの ID や番号を取り出す関数が提供されている。 ROWID をハードコーディングによって分割する SQL を組むことは上位互換性を失うことになるので避ける。 (外部文字 ROWID は アドレスを BASE64 でエンコードしたもの…と書かれている。しかし実際に比較してみると微妙に合っていない。深く考えるのはやめておこう。)

ROWID の正体は、行ディレクトリの番号まで*2 を特定する情報。(※あくまで Oracle Database 概要を読んでの推測)

ROWIDを使用した場合の列データまでのアクセスパスは
ROWID(≒データブロックの行ディレクトリのアドレス) > 行ヘッダ > 列ヘッダ > 列データ ではないかと思う。

内部 ROWID

Oracle のサーバー・プログラムが実際にハンドリングする際の ROWID。これは 6 バイトで構成されている。
制限付き内部 ROWID とも書かれている。

(根拠のない予想)
Oracle 的にはシステムでユニークなオブジェクトID には興味がなさそうなので、10 バイトの ROWID からオブジェクトIDあたりを短くしたか削ったような気がする。都合よく解釈するとオブジェクトID (6 バイト) は 外部文字 ROWID(18 バイト) の 1/3 だから ROWID 10 バイト:内部 ROWID 6 バイトでなんとなく計算もあう。

制限付き ROWID

下位互換用 (Oracle 7用)

ファイル番号、ブロック番号、行番号によりデータ行の「物理的」な位置を示す。

Oracle の接続は過去2つのメジャーバージョンの接続が原則?であるから Oracle 11 がリリースされると 廃止されるようなことがあるかもしれない。

論理 ROWID (UROWID)

索引構成表は索引のリーフにデータを格納する表で、永続的な物理ROWIDを持つことができない。 そのために論理的な位置を示す UROWID (Universal ROWID)がある。(Oracle 8i:8.1.5〜)

プライマリキー 以外の更新では変更されることがない点が特徴。 外部表 の ROWID も、この 論理ROWID のようである。索引構成表 も UROWID である。



ROWID 擬似列に関連する内容

日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ 会員制(無料)の公式技術サイト

*1 DBA_OBJECTS の DATA_OBJECT_ID(≠ OBJECT_ID)と同じ
*2 はじめは、行ヘッダと推測していたが、ブロック内の断片化の圧縮が行われることから永続性が保てない。ブロック内連鎖という選択もあるが連鎖が常態になるので違う