我有这个问题:
$sql = "SELECT
catalogs_values.name as word, catalogs.name as catalog
FROM
catalogs_values
INNER JOIN
catalogs ON catalogs_values.catalog_id = catalogs.id
WHERE
catalogs_values.id NOT IN (SELECT
valueid
FROM
monitor
WHERE
userid = $user_id)
AND catalogs_values.checked = 0
ORDER BY RAND()
LIMIT 1";
在我的表中,我有大约100万条记录,我的查询非常慢。你能建议一些改进吗?
答案 0 :(得分:1)
通过Mysql的RAND排序总是很慢,我用一种非常快速的方法对它进行排序:
一旦你确定ID存在退出循环,就会有你的随机ID
$SQL = " SELECT MAX( id ) as x FROM table ";
$query = mysql_query($SQL);
$x = mysql_fetch_assoc($query);
$max = $x['x'];
$ok = false;
while($ok == false){
$id = rand(1, $max);
$SQL = "SELECT id FROM table WHERE id = ".$id." LIMIT 1";
$query = mysql_query($SQL);
$record = mysql_fetch_assoc($query);
if((int)$record['id'] > 0){
$ok = true;
}
}
//your ID is: $record['id'];
答案 1 :(得分:1)
MediaWiki(想想维基百科的random article page)通过为每一行random value分配一个,将其添加到索引,然后使用索引选择来实现这一点:
SELECT * from `some_table` where `my_rand_column` >= RAND() LIMIT 1;
答案 2 :(得分:0)
尝试将not in
替换为left outer join
或not exists
:
SELECT cv.name as word, c.name as catalog
FROM catalogs_values cv INNER JOIN
catalogs c
ON cv.catalog_id = c.id LEFT JOIN
monitor m
on cv.id = m.valueid and userid=$user_id
WHERE m.valueid is null and cv.checked = 0
ORDER BY RAND()
LIMIT 1;
这可能会解决性能问题。
如果不是,您可能需要另一种方法来获取随机行。一种简洁的方法是选择随机行的子集,然后只选择一个:
select word, catalog
from (SELECT cv.name as word, c.name as catalog
FROM catalogs_values cv INNER JOIN
catalogs c
ON cv.catalog_id = c.id LEFT JOIN
monitor m
on cv.id = m.valueid and userid=$user_id
WHERE m.valueid is null and cv.checked = 0 and rand() < 0.001
) t
ORDER BY RAND()
LIMIT 1;
内部查询选择大约一千行中的一行(该比例可能需要根据与其他各种条件匹配的行数而变化)。然后将此简化集传递给order by rand()
方法,以便只选择一个。
答案 3 :(得分:0)
你可以采取这样的随机数:
$whoToTake = rand(1, 1000000);
或者如果您希望它是动态的,请进行简单的计数
select count(id) from table;
$max = THE_RESULT_OF_THE_QUERY
$whoToTake = rand(1, $max);
现在做一个简单的查询
select *
from table
limit 1 offset {$whoToTake}
这会快得多
答案 4 :(得分:0)
这是关于freenode IRC的#mysql的一个反复出现的问题。
看看Jan Kneschke的this blog post。
它概述了如何优化ORDER BY RAND() LIMIT 1
,这样您就不必首先排序所有行,然后抛弃所有内容,除了您要保留的那一行。
Jan在没有完全剥夺他的博客文章的情况下更详细地解释了这一点。