SQL で 全レコードからランダムに行を取り出す

SELECT のサンプリング機能を使用してテーブルからブロックレベルか行レベルでランダムにレコードを取り出す。
ブロックレベルでサンプリングした場合には、取得するブロック先が使用済みの未使用領域の場合もあるので 0 件になる可能性がある。

大規模表 のインデックスが未設置の項目に対して 集計関数 を用いて平均長や分散を採取するときには、データベースにかけるメモリやディスクなどへの負荷をかなり減少させることができる。

全体からランダムに指定した百分率分のレコードを取り出す

結果の全体レコードから行単位で 5% をランダムに抽出する。

SELECT
	USER_MASTER.USER_ID, USER_MASTER.USER_NAME, DEPT.DEPT_NAME
FROM
	USER_MASTER, DEPT
	SAMPLE(5)		-- ← ここでサンプル句を指定する
WHERE
	USER_MASTER.DEPT_NO = DEPT.DEPT_NO

テーブル結合が使えないバージョンはインラインビューに変換する。

  • SAMPLE のオプション
SAMPLE [BLOCK]( sample_percent ) [ SEED ( seed_value ) ]
BLOCK
ブロック単位でサンプリング(省略時は、行単位でサンプリング)
但し、テーブルフルスキャン または INDEX FAST FULL SCAN になる場合
sample_percent
0.000001 以上 100 未満で指定
サンプリングの数値が小さすぎると行が戻らない場合がある。
SEED seed_value Oracle 10g
seed_value (8バイト) には、0(ゼロ)〜 4294967295 を指定する。 同じ値を指定した場合には検索結果は同じとなる。デフォルトは自動で ランダム値 となる。

サンプルスキャンの制限事項と問題点

SAMPLE 句には高速にサンプリングするために結構多くの制限事項と限定仕様?があるので注意する。

SQL> SELECT * FROM ALL_CATALOG SAMPLE(50);
行1でエラーが発生しました。:
ORA-01445: たとえば、キー保存表のない結合ビューからROWIDを選択できません

エラーメッセージから邪推すると行単位に ROWID が一意に決定できないビューにも使用できないかも? (例: UNION / ITERSECT / MINUS あたりを使用した更新不可能なビュー:未検証)
外部表 には UROWID が存在するので使えると思われる。(これも未検証)

  • テーブルに別名を使用するとエラーになった。(Oracle 10g R2:10.2.0.1.0)
  • INSERT 〜 SELECT で SAMPLE 句を使用するとエラーになった。(Oracle 8i 以下:ターミナルリリースでは未確認)


ライセンス

サンプル・スキャンを使用するには Oracle 8i エンタープライズ版、または、Oracle 9i スタンダード版以上が必要

サイト統合にともない代替情報の URL は不明

テーブル・データをランダムサンプリングするの関連トピックス

日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ Oracle のライセンスがわからない…
Oracle Direct (ネットで聞いても最後はここで要確認)