MySQL select 3 UNIQUE random ID rows fast WHERE
I need to be able to select 3 Unique random MySQL ID rows from a table that is progressively growing and growing over time, AND have a WHERE 'status' = 'available'. So it only picks the id number if status = available.
There will be no gaps as all data is kept for record keeping compliance, if data is deleted by the user it is not actually deleted just STATUS is marked 'deleted'.
I've read many posts about the subject but it all seems to boil down to picking just 1 result, and then repeating it 3 times, problem is, it might pick the same ID again, so any solution to my problem will be much appreciated.
I was looking at doing something like this (taken from here ... MySQL select 10 random rows from 600K rows fast)
SELECT id FROM table AS r1 JOIN (SELECT (RAND() * (SELECT MAX(id) FROM table)) AS id2) AS r2 WHERE r1.id >= r2.id2 AND status = 'available' ORDER BY r1.id ASC LIMIT 1
Which gives me what I need, but it only returns 1 random Unique 'pick', plus IF I limit it to 3, it does not always pick 3, and if it does pick 3 they always seem to be sequential which is not random!
Is there a way to repeat the query, store the ID picked and keep looping / running the query until 3 ID's are picked AT RANDOM that are Different. This is my question :)
Did you try:
SELECT * FROM mytable WHERE status = 'available' ORDER BY RAND( ) LIMIT 0,3;
SELECT DISTINCT * FROM table WHERE status = 'available' ORDER BY RAND() LIMIT 3
The DISTINCT clause shall prevent repeated values. ORDER BY RAND() will randomly organize the result.
See the following; where it talks about "gaps", you have the equivalent (status=deleted) http://mysql.rjweb.org/doc.php/random#case_auto_increment_with_gaps_1_or_more_rows_returned (and look around in that link for variants)
- Requirement: AUTO_INCREMENT, possibly with gaps due to DELETEs, etc
- Flaw: Only semi-random (rows do not have an equal chance of being picked), but it does partially compensate for the gaps
- Flaw: The first and last few rows of the table are less likely to be delivered.
This gets 50 "consecutive" ids (possibly with gaps), then delivers a random 10 of them.
-- First select is one-time: SELECT @min := MIN(id), @max := MAX(id) FROM RandTest; SELECT a.* FROM RandTest a JOIN ( SELECT id FROM ( SELECT id FROM ( SELECT @min + (@max - @min + 1 - 50) * RAND() AS start FROM DUAL ) AS init JOIN RandTest y WHERE y.id > init.start ORDER BY y.id LIMIT 50 -- Inflated to deal with gaps ) z ORDER BY RAND() LIMIT 10 -- number of rows desired ) r ON a.id = r.id;
Yes, it is complex, but yes, it is fast, regardles of the table size.