

MySQLでORDER BY RAND()を使わずにランダム行を取る方法
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
背景
ORDER BY RAND() LIMIT n でランダムな行を取る方法はよく見るけど、これはテーブル全体に対してRAND()を評価してからソートするので、行数が多いテーブルだと遅い。インデックスも効かない。
代替として、JOINで先にランダムなIDを1つ作ってから絞り込むやり方がある。
やり方
SELECT t.*FROM TableName AS tJOIN ( SELECT ROUND(RAND() * (SELECT MAX(id) FROM TableName)) AS rand_id) AS rON t.id >= r.rand_idORDER BY t.idLIMIT 1;仕組み
- サブクエリで
MAX(id)を1回だけ取得する RAND()を掛けて0〜MAX(id)の範囲のランダムな値を1つ生成する- その値に対して
id >= rand_idで一番近い行を1件取る
ORDER BY RAND() のように全行にRAND()を計算するわけではないので、大きいテーブルでも軽い。
注意点
- idに欠番(削除された行など)があると、その付近の行が選ばれやすくなる。厳密な一様分布にはならない
id >= rand_idの条件で一番若いIDにヒットする仕組みなので、末尾側のIDがやや選ばれやすくなる傾向がある。実機で分布を検証したわけではないので、あくまで理屈の上での話- 複数件ほしい場合、このクエリをそのまま
LIMIT 10にしても1件しか返らない。複数件必要ならアプリ側でループを回すか、UNIONで複数回実行する必要がある - 前提として、idが
AUTO_INCREMENTの連番であること