How can i optimize MySQL's ORDER BY RAND function?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
ORDER BY RAND() in MySQL generates a random value for every row in the table, sorts the entire result set by these values, then returns the top N rows. This is O(n log n) where n is the total row count, making it extremely slow on large tables. Optimized alternatives include using a random offset with LIMIT, joining against a random ID subquery, or maintaining a pre-shuffled column. The right approach depends on whether you need one random row or many, and whether gaps exist in the ID column.
The Problem with ORDER BY RAND()
On a table with 1 million rows, this:
- Generates 1 million random values
- Sorts all 1 million rows
- Returns only 5
The execution time grows linearly with table size regardless of how many rows you request.
Optimization 1: Random Offset (Single Row, No Gaps)
If IDs are sequential with no gaps:
This picks a random ID and fetches the row at or after that ID. The index on id makes this nearly instant.
For multiple random rows:
Optimization 2: Random Offset with LIMIT/OFFSET
This works with any table structure (including gaps in IDs) but OFFSET still scans rows to skip, so it is slow for large offsets.
Optimization 3: Join Against Random ID
This uses the primary key index for a fast lookup. The distribution is slightly biased toward IDs that follow large gaps, but it is fast.
For multiple rows:
Optimization 4: Pre-Computed Random Column
Add a random column that you periodically shuffle:
This gives consistent O(log n) lookups via the index. The tradeoff is that the same "random" order persists until you re-shuffle.
Optimization 5: Application-Level Randomization
Optimization 6: Sampling with TABLESAMPLE (MySQL 8.0+)
MySQL 8.0 does not have TABLESAMPLE, but you can use the performance schema or InnoDB page sampling for approximate random sampling:
Performance Comparison
| Method | Time (1M rows) | Uniform? | Gaps OK? |
ORDER BY RAND() | ~2-5 seconds | Yes | Yes |
| Random ID join | ~1-5 ms | Slightly biased | Yes |
| Random offset | ~1-5 ms | Yes | No gaps |
| Pre-computed column | ~1-5 ms | Yes | Yes |
| Application random | ~1-10 ms | Yes | Yes |
LIMIT OFFSET | ~0-2 seconds | Yes | Yes |
Common Pitfalls
- Assuming ORDER BY RAND() is optimized for small LIMIT values: MySQL does not short-circuit — it generates a random value for every row regardless of the LIMIT.
ORDER BY RAND() LIMIT 1on a 10M row table is just as slow asORDER BY RAND() LIMIT 10000. - Using OFFSET for random access on large tables:
LIMIT 1 OFFSET 500000causes MySQL to scan and discard 500,000 rows before returning the result. For large tables, the random ID join approach is much faster because it uses the index directly. - Not accounting for ID gaps:
FLOOR(RAND() * MAX(id))can land on a deleted ID. Always useWHERE id >= rand_id ORDER BY id LIMIT 1to find the next existing row, notWHERE id = rand_idwhich returns nothing for gaps. - Biased distribution with ID-based methods: When large ranges of IDs are deleted, rows immediately after gaps are oversampled because more random values map to them. If uniform distribution is critical, use the offset method or pre-computed random column instead.
- Re-shuffling the random column too frequently: Updating
rand_sorton millions of rows is an expensive write operation. Schedule it during low-traffic periods and accept that randomness is "stale" between shuffles. For most use cases, daily re-shuffling is sufficient.
Summary
ORDER BY RAND()is O(n log n) and should be avoided on tables with more than a few thousand rows- For single random rows, use a random ID join (
WHERE id >= FLOOR(RAND() * MAX(id))) - For multiple random rows, generate random IDs in the application layer and fetch with
WHERE id IN (...) - Use a pre-computed
rand_sortcolumn with an index for consistently fast random access - Application-level randomization gives full control over distribution and avoids database overhead
- The random ID join is slightly biased for tables with large ID gaps — use offset-based methods when uniform distribution is critical
Related reading
- How can I output MySQL query results in CSV format?
- How can I output MySQL query results in CSV format?
- How can I pass environment variables to mongo docker-entrypoint-initdb.d?
- How can I prevent SQL injection in PHP?
- How can I prevent synchronous continuations on a Task?
- How can I profile a multithread program in Python?
- How can I provide different database configurations with Spring Boot?
- How can I put a database under git version control?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.