MySQL Select Random X Entries - Optimized - mysql

MySQL what's the best way to select X random entries (rather than just one) - optimization for heavy use, i.e. on main page of a domain.
Supposedly just blindly using MySQL rand() is going to make this rather scary for large databases - please give me a better optimization answer than that!

the solution is use php
look at this article that choose the solution number 3 as faster
http://akinas.com/pages/en/blog/mysql_random_row/
Solution 3 [PHP]
$offset_result = mysql_query( " SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` ");
$offset_row = mysql_fetch_object( $offset_result );
$offset = $offset_row->offset;
$result = mysql_query( " SELECT * FROM `table` LIMIT $offset, 1 " )
the
Solution 4 [SQL] (Second in fast)
SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;

I had an issue with the ids. The id was auto generated but the minimum id was very large with respect to the number of total records. So I made a little changes to make the query more randomized, but a little slower though.
SELECT * FROM 'table' WHERE id >= (SELECT (FLOOR( MAX(id) * RAND()) + MIN(id)) FROM 'table' ) ORDER BY id LIMIT 10

Related

Mysql improve sampling query speed

I have a table with 3,000,000 records.I tried to randomly extract 300,000 records using the following method,but it takes about 7 minutes.
SELECT * FROM mytable WHERE `class`='faq' ORDER BY RAND() LIMIT 300000
I want to improve the speed of random extraction, what should I do?
Mysql version is 5.6.
The cost is most likely due to sorting all the matching data. You don't specify how many rows match the condition, so this sort is likely to be some fraction of 3,000,000 rows.
If you can deal with approximately 300,000, you can use sampling logic in the WHERE clause:
SELECT t.*
FROM mytable t CROSS JOIN
(SELECT COUNT(*) as cnt
FROM t
WHERE class = 'faq'
) x
WHERE t.class = 'faq' AND
rand() < (300000 / cnt);
To be more precise, you can take a slightly larger random sample and then use order by/limit:
SELECT t.*
FROM mytable t CROSS JOIN
(SELECT COUNT(*) as cnt
FROM t
WHERE class = 'faq'
) x
WHERE t.class = 'faq' AND
rand() < (300000 / cnt) * 1.1
ORDER BY rand()
LIMIT 300000;

Select limit percent

I want
example 10% of records in table
not 10 records
This query run in SQL Server
select top 10 percent * from tablename
Why this query in MySQL do not run?
select top 10 percent * from tablename
You could do it with a subquery, this is pretty basic since you want everything in one table:
SELECT *
FROM (
SELECT tablename.*, #counter := #counter +1 AS counter
FROM (select #counter:=0) AS initvar, tablename
ORDER BY value DESC
) AS X
where counter <= (10/100 * #counter);
ORDER BY value DESC
For MySQL use order by or limit
select * from tablename order by percent desc limit 10
TOP clause works on MSSQL server not sql.

Get random record in a set of results

I have a simple MySQL query like this:
SELECT * ,
( MATCH (table.get) AGAINST('playstation ' IN BOOLEAN MODE) )
+ ( table.get LIKE '%playstation%') AS _score
FROM table
JOIN users on table.id_user = users.id
WHERE table.expire_datetime > 1375997618
HAVING _score > 0
ORDER BY RAND(table.id) ,_score DESC ;
If I run this query in MySQL, it returns usually more then 1 record, now I would like to LIMIT 1 and get one of them randomly, not always the same record.
Is it possible?
select * from <my_table>
ORDER BY RAND()
LIMIT 4
You would quit seeding the random number generator. My guess is that it is returning the first table id encountered, so the numbers are generated in the same sequence:
SELECT * ,
( MATCH (table.get) AGAINST('playstation ' IN BOOLEAN MODE) )
+ ( table.get LIKE '%playstation%') AS _score
FROM table
JOIN users on table.id_user = users.id
WHERE table.expire_datetime > 1375997618
HAVING _score > 0
ORDER BY RAND()
LIMIT 1;
As I understand problem in ,_score ?
Try this:
Select * FROM (
***your sql query***
) as t
ORDER BY RAND()
LIMIT 1

Mysql get top half of table then bottom half of table

I need to get the top half of my table in my first query and in the next query I need the bottom half.
I tried doing this for the top but it wont work
SELECT * FROM t_domains WHERE type_domain='radio' ORDER BY
date_created DESC LIMIT 0, (COUNT(*) / 2)
I need it as two queries for my function to work.
Anybody have any pointers or tips?
I would suggest doing 2 query's:
select count(*) from t_domains
to get the total count, and then get the data you want by using limit and offset:
select * from t_domains limit count/2
for the top and
select * from t_domains offset count/2
for the lower half......
This approach gives you also a way to limit the query's in another situation: what if the table contains 1 million records?
for first half
mysql-> SET #n := 0
mysql-> SELECT *,nnn FROM (
SELECT *, #n := #n + 1 AS nnn FROM t_domains ORDER BY date_created
) AS t
WHERE nnn <= ( SELECT COUNT(date_created) / 2 FROM t_domains ) AND type_domain = 'radio'
for second half, change here WHERE nnn <= this "<" on this ">"
As explained in MySQL's official documentation, LIMIT's two arguments must both be CONSTANTS except for prepared statements and stored programs. It does not seem very easy to simply store the count and later use it in a LIMIT clause.
As of version 8.0, MySQL has provided a ROW_NUMBER() function, which provides a much simpler solution than other answers have pointed out.
set #count=(select count(*)/2 from t_domains);
select * from (
select *, ROW_NUMBER() over (order by date_created desc) as row_num
from t_domains
) as t
where row_num <= #count
;
You may also check RANK(), which considers rows with equal values to have the same "ranking".
This always works.
Store the count
SELECT COUNT(*) FROM t_domains WHERE type_domain='radio'
Then use the stored count.
SELECT * FROM t_domains WHERE type_domain='radio' ORDER BY
date_created DESC LIMIT 0, {$stored_count/2}

How to get mysql random integer range?

I am trying to generate a random integer for each row I select between 1 and 60 as timer.
SELECT downloads.date, products.*, (FLOOR(1 + RAND() * 60)) AS timer
I have searched and keep coming up to this FLOOR function as how to select a random integer in a range. This is giving me a 1 for every row.
What am I missing?
I am on mysql 5.0.75
Heres the rest of the query I belive it might be a nesting issue
SELECT *
FROM (
SELECT downloads.date, products.*, FLOOR(1 + (RAND() * 60)) AS randomtimer,
(
SELECT COUNT( * )
FROM distros
WHERE distros.product_id = products.product_id
) AS distro_count,
(SELECT COUNT(*) FROM downloads WHERE downloads.product_id = products.product_id) AS true_downloads
FROM downloads
INNER JOIN products ON downloads.product_id = downloads.product_id
) AS count_table
WHERE count_table.distro_count > 0
AND count_table.active = 1
ORDER BY count_table.randomtimer , count_table.date DESC LIMIT 10
This is working for me. Your mysql version maybe?
SELECT id, (FLOOR( 1 + RAND( ) *60 )) AS timer
FROM users
LIMIT 0 , 30
The output of the RAND function will always be a value between 0 and 1.
Try this:
SELECT downloads.date, products.*, (CAST(RAND() * 60 AS UNSIGNED) + 1) AS timer
Old question, but always actual problem.
Here a way to create a MySQL function random_integer() based on manual :
CREATE FUNCTION random_integer(value_minimum INT, value_maximum INT)
RETURNS INT
COMMENT 'Gets a random integer between value_minimum and value_maximum, bounds included'
RETURN FLOOR(value_minimum + RAND() * (value_maximum - value_minimum + 1));
SELECT ALL random_integer(1, 60) AS timer;
I'm running your query and it does give me a random number for each row.... maybe has something to do with the name of the random (timer)?
You can increase the number multiplied by the number of records in the table.
SELECT id,
(FLOOR( (SELECT MIN(id) FROM your_table ) + RAND( ) * 1000000 ) ) AS timer
FROM your_table
LIMIT 0 , 30