How can i optimize MySQL's ORDER BY RAND() function?
Try this:
SELECT *
FROM (
SELECT @cnt := COUNT(*) + 1,
@lim := 10
FROM t_random
) vars
STRAIGHT_JOIN
(
SELECT r.*,
@lim := @lim - 1
FROM t_random r
WHERE (@cnt := @cnt - 1)
AND RAND(20090301) < @lim / @cnt
) i
This is especially efficient on MyISAM
(since the COUNT(*)
is instant), but even in InnoDB
it's 10
times more efficient than ORDER BY RAND()
.
The main idea here is that we don't sort, but instead keep two variables and calculate the running probability
of a row to be selected on the current step.
See this article in my blog for more detail:
- Selecting random rows
Update:
If you need to select but a single random record, try this:
SELECT aco.*
FROM (
SELECT minid + FLOOR((maxid - minid) * RAND()) AS randid
FROM (
SELECT MAX(ac_id) AS maxid, MIN(ac_id) AS minid
FROM accomodation
) q
) q2
JOIN accomodation aco
ON aco.ac_id =
COALESCE
(
(
SELECT accomodation.ac_id
FROM accomodation
WHERE ac_id > randid
AND ac_status != 'draft'
AND ac_images != 'b:0;'
AND NOT EXISTS
(
SELECT NULL
FROM accomodation_category
WHERE acat_id = ac_category
AND acat_slug = 'vendeglatohely'
)
ORDER BY
ac_id
LIMIT 1
),
(
SELECT accomodation.ac_id
FROM accomodation
WHERE ac_status != 'draft'
AND ac_images != 'b:0;'
AND NOT EXISTS
(
SELECT NULL
FROM accomodation_category
WHERE acat_id = ac_category
AND acat_slug = 'vendeglatohely'
)
ORDER BY
ac_id
LIMIT 1
)
)
This assumes your ac_id
's are distributed more or less evenly.
It depends on how random you need to be. The solution you linked works pretty well IMO. Unless you have large gaps in the ID field, it's still pretty random.
However, you should be able to do it in one query using this (for selecting a single value):
SELECT [fields] FROM [table] WHERE id >= FLOOR(RAND()*MAX(id)) LIMIT 1
Other solutions:
- Add a permanent float field called
random
to the table and fill it with random numbers. You can then generate a random number in PHP and do"SELECT ... WHERE rnd > $random"
- Grab the entire list of IDs and cache them in a text file. Read the file and pick a random ID from it.
- Cache the results of the query as HTML and keep it for a few hours.