DB

MySQLでランダムにレコードを取得する

こんにちは、フリーランスエンジニアのせいや(@knkSeiya)です。

先日、MySQLでランダムにレコードを取得したい機会がありました。

そういえばどういうクエリを書けばランダムにレコードが取れるんだっけ?ってなったのでその備忘録です。

MySQLでランダムにレコードを取得する

MySQLでランダムにレコードを取得するのはいくつかの方法があるようですが、今回は一番簡単な方法を紹介します。

方法:ORDER BY RAND()を使う

クエリにORDER BYを指定し、RAND()を使います。

RANDは「0 <= value < 1」となるようなvalueを返してくれる関数です。

例として、以下のテーブルを用意しました。

mysql> DESC fruits;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(255) | NO   |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM fruits;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | りんご       |
|  2 | バナナ       |
|  3 | メロン       |
|  4 | いちご       |
|  5 | オレンジ     |
+----+--------------+
5 rows in set (0.00 sec)

このテーブルからランダムにレコードを取得してみます。

mysql> SELECT * FROM fruits ORDER BY RAND() LIMIT 1;
+----+-----------+
| id | name      |
+----+-----------+
|  4 | いちご    |
+----+-----------+
1 row in set (0.00 sec)

取れました⊂(´ω`)⊃

だけど注意点があって、RAND()でORDER BYすると「Using temporary; Using filesort」が使われるようです。

mysql> EXPLAIN SELECT * FROM fruits ORDER BY RAND() LIMIT 1;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                           |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
|  1 | SIMPLE      | fruits | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | Using temporary; Using filesort |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)

レコード数が少なければORDER BY RAND()は一番簡単にランダム取得できる方法ですが、大量のレコードに実行するのは危険です。たぶんめっちゃ遅くなります( ; ^ω^ )

  • レコードのランダム取得は「ORDER BY RAND()」が簡単
  • Using temporary; Using filesortになる(データ量によっては遅くなる)

おまけ:FuelPHPのORMでの指定

FuelPHPのORMでのランダム取得の書き方。

find('first', ['order_by' => [DB::expr('RAND()')]])

FuelPHPのクエリビルダでMySQLの関数を使いたい場合はDB::expr()で囲ってやる必要があります。

せいや

用法・容量を守って正しくお使いください!(ぶん投げ