【SQL】ランダムにソートしてデータを取得する方法

データベースからレコードを取得するとき、ランダムな順番で表示したいシーンは意外と多いですよね。クイズゲームや抽選ロジック、サンプリングなど、ランダムなデータ取得の方法を覚えておくと便利です。

MySQL編 — RAND()でランダムソート

MySQL でデータをランダムにソートするには、ORDER BY RAND() を使うのが手軽です。

SELECT *
FROM テーブル名
ORDER BY RAND();

RAND() は 0 以上 1 未満の乱数を返す関数です。

結果がランダムになる一方、全行に対して乱数が評価されるため、大量のデータがある場合はパフォーマンスが低下しやすい点に注意が必要です。

PostgreSQL編 — RANDOM()でランダムソート

PostgreSQL の場合は、MySQL の RAND() と似たような役割をする RANDOM() 関数を使用します。

SELECT *
FROM テーブル名
ORDER BY RANDOM();

RANDOM() は 0 以上 1 未満の乱数を返す関数です。

大量データを扱う場合は、やはりパフォーマンスに注意しましょう。

SQLite編 — RANDOM()でランダムソート

SQLite でも、PostgreSQL と同様に RANDOM() を使ってランダムソートが可能です。

SELECT *
FROM テーブル名
ORDER BY RANDOM();

SQLite の RANDOM() 関数は、整数の乱数を生成しますが、ORDER BY での挙動としては問題なくランダム化が行えます。

大きいテーブルで使う際はパフォーマンスを考慮しましょう。

SQL Server編 — NEWID()でランダムソート

SQL Server には MySQL や PostgreSQL のように行ごとに異なる数値を返すランダム関数がありません。RAND() を直接 ORDER BY で利用すると、全行に対して同じ値を返してしまいます。そのため、代わりに NEWID() を使うのが一般的です。

SELECT *
FROM テーブル名
ORDER BY NEWID();

NEWID() はユニークなGUID(グローバルユニークID)を生成し、結果として行の並びがランダムになります。

ただし、こちらも大量のレコードを処理する場合はパフォーマンスに注意が必要です。

大量データに対するパフォーマンス上の注意

ORDER BY RAND(), ORDER BY RANDOM(), ORDER BY NEWID() などは、すべての行に対して乱数やGUIDを生成→それに基づいてソート という流れをとるため、テーブルに数百万件以上のデータがあるような大規模環境だと負荷が非常に高くなります。

サンプリングテーブルを利用する

もし定期的にランダムデータを扱う必要があるなら、メインのテーブルとは別に、あらかじめサンプリング用のテーブルを作成しておき、そこからランダムソートして取得する方法も検討できます。

IDの範囲を利用して乱数で抽出する

テーブルの主キーやIDが連番であれば、乱数でIDを生成し、そのIDが該当するレコードを取得する方式もあります。ランダムに取得したい件数分だけ ID を抽出し、それを WHERE id IN (…) で取得するなど、工夫すると効率よくランダムデータが取得できます。

アプリケーション側で処理する

SQL でランダムソートを行わず、アプリケーション側で取得したデータをシャッフルするのも1つの手です。サーバーリソースや開発環境によっては、こちらのほうがパフォーマンスの面で優れている場合もあります。

まとめ

ランダムソート自体はシンプルな一行のSQLで実装できますが、データ量が多い場合にはパフォーマンスに注意が必要です。ランダム取得の方法は下記のように覚えておきましょう。

  • MySQL: ORDER BY RAND()
  • PostgreSQL / SQLite: ORDER BY RANDOM()
  • SQL Server: ORDER BY NEWID()

必要に応じて、サンプリングテーブルを用意したり、アプリケーション側で実装したりと工夫してみてください。