从MySQL中选择可变数量的随机记录
我想从数据库中显示一个随机记录。如果我选择,我希望能够显示X个随机记录。因此,我需要从随机选择的ID列表中选择最前面的X条记录。从MySQL中选择可变数量的随机记录
(除非地球大小显着增加,否则将不会有超过500条记录可供选择,目前有66条可能。)
此功能可以使用,但我怎样才能让它变得更好?
/***************************************************/
/* RandomSite */
//****************/
// Returns an array of random site IDs or NULL
/***************************************************/
function RandomSite($intNumberofSites = 1) {
$arrOutput = NULL;
//open the database
GetDatabaseConnection('dev');
//inefficient
//$strSQL = "SELECT id FROM site_info WHERE major <> 0 ORDER BY RAND() LIMIT ".$intNumberofSites.";";
//Not wonderfully random
//$strSQL = "SELECT id FROM site_info WHERE major <> 0 AND id >= (SELECT FLOOR(COUNT(*) * RAND()) FROM site_info) ORDER BY id LIMIT ".$intNumberofSites.";";
//Manual selection from available pool of candidates ?? Can I do this better ??
$strSQL = "SELECT id FROM site_info WHERE major <> 0;";
if (is_numeric($intNumberofSites))
{
//excute my query
$result = @mysql_query($strSQL);
$i=-1;
//create an array I can work with ?? Can I do this better ??
while ($row = mysql_fetch_array($result, MYSQL_NUM))
{
$arrResult[$i++] = $row[0];
}
//mix them up
shuffle($arrResult);
//take the first X number of results ?? Can I do this better ??
for ($i=0;$i<$intNumberofSites;$i++)
{
$arrOutput[$i] = $arrResult[$i];
}
}
return $arrOutput;
}
更新问题: 我知道的ORDER BY RAND(),我只是不想使用它,因为有传言它不是在缩放和性能最好的。我对我的代码过度批评。我有作品,ORDER BY RAND()的作品,但我可以做得更好吗?
更新更新 ID中有空洞。没有大量的流失,但发生的任何流失都需要我们团队的批准,因此可以处理以缓存任何缓存。
感谢您的回复!
为什么不在你的数据库查询的orderby中使用Rand函数?然后,你不必进入代码中随机等等
喜欢的东西(我不知道这是否是合法的)
Select *
from site_info
Order by Rand()
LIMIT N
其中N是你想要的记录数。 ..
编辑
你有没有你的代码与查询解决方案?我想你只是在这里预先优化。
他的代码中被注释掉了,标记为低效。 – 2009-02-17 21:15:22
嗯,我不觉得Sheepish ... – 2009-02-17 21:16:35
mysql_query("SELECT id FROM site_info WHERE major <> 0 ORDER BY RAND() LIMIT $intNumberofSites")
编辑 妈,JPunyon是有点快:)
我会简单地使用rand()函数(我假设你正在使用MySQL)...
SELECT id, rand() as rand_idx FROM site_info WHERE major <> 0 ORDER BY rand_idx LIMIT x;
如果你不想用rand()命令来选择。
相反shuffeling的,对结果使用array_rand:
$randKeys = array_rand($arrResult, $intNumberofSites);
$arrOutput = array_intersect_key(array_flip($randKeys), $arrResult);
编辑:归还钥匙的数组没有新的数组与关键=>值
嗯,我不认为ORDER BY RAND ()在只有66行的表中会很慢,但是无论如何你可以看看几个不同的解决方案。
数据是否真的稀疏和/或经常更新(所以ID有很大的差距)?
假设它不是很稀疏,您可以从表中选择最大ID,使用PHP的内置随机函数从1到最大ID之间选择N个不同的数字,然后尝试从这些ID获取行桌子。如果您获取的行数少于您选择的数字,请获取更多随机数并重试,直到获得所需的行数。这可能不是特别快。
如果数据很稀疏,我会设置一个辅助的“id-type”列,确保它是连续的。因此,如果表格中有66行,请确保新列包含值1-66。每当将行添加到表中或从表中移除时,都必须执行一些工作来调整此列中的值。然后使用与上述相同的技术,在PHP中选择随机ID,但不必担心“丢失ID?重试”情况。
尝试这种情况:
SELECT
@nv := @min + (RAND() * (@max - @min))/@lc,
(
SELECT
id
FROM site_info
FORCE INDEX (primary)
WHERE id > @nv
ORDER BY
id
LIMIT 1
),
@max,
@min := @nv,
@lc := @lc - 1
FROM
(
SELECT @min := MIN(id)
FROM site_info
) rmin,
(
SELECT @max := MAX(id)
FROM site_info
) rmax,
(
SELECT @lc := 5
) l,
site_info
LIMIT 5
这将在每次迭代使用索引,以降序选择随机ID。
虽然你得到的结果较少,但你得到的结果不大,因为它不会给错过的ID带来第二次机会。
您选择的行数越多,机会就越大。
我与JPunyon。使用ORDER BY RAND() LIMIT $N
。我想你会从$arrResult
中得到更大的性能,它具有和洗牌这么多(未使用)的条目,而不是使用MySQL RAND()函数。
function getSites ($numSites = 5) {
// Sanitize $numSites if necessary
$result = mysql_query("SELECT id FROM site_info WHERE major <> 0 "
."ORDER BY RAND() LIMIT $numSites");
$arrResult = array();
while ($row = mysql_fetch_array($result,MYSQL_NUM)) {
$arrResult[] = $row;
}
return $arrResult;
}
这里有三个功能,我写和测试
我的回答
/***************************************************/
/* RandomSite1 */
//****************/
// Returns an array of random rec site IDs or NULL
/***************************************************/
function RandomSite1($intNumberofSites = 1) {
$arrOutput = NULL;
GetDatabaseConnection('dev');
$strSQL = "SELECT id FROM site_info WHERE major <> 0;";
if (is_numeric($intNumberofSites))
{
$result = @mysql_query($strSQL);
$i=-1;
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arrResult[$i++] = $row[0]; }
//mix them up
shuffle($arrResult);
for ($i=0;$i<$intNumberofSites;$i++) {
$arrOutput[$i] = $arrResult[$i]; }
}
return $arrOutput;
}
JPunyon和许多其他
/***************************************************/
/* RandomSite2 */
//****************/
// Returns an array of random rec site IDs or NULL
/***************************************************/
function RandomSite2($intNumberofSites = 1) {
$arrOutput = NULL;
GetDatabaseConnection('dev');
$strSQL = "SELECT id FROM site_info WHERE major<>0 ORDER BY RAND() LIMIT ".$intNumberofSites.";";
if (is_numeric($intNumberofSites))
{
$result = @mysql_query($strSQL);
$i=0;
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arrOutput[$i++] = $row[0]; }
}
return $arrOutput;
}
OIS有创造性的解决方案会议的打算的我题。
/***************************************************/
/* RandomSite3 */
//****************/
// Returns an array of random rec site IDs or NULL
/***************************************************/
function RandomSite3($intNumberofSites = 1) {
$arrOutput = NULL;
GetDatabaseConnection('dev');
$strSQL = "SELECT id FROM site_info WHERE major<>0;";
if (is_numeric($intNumberofSites))
{
$result = @mysql_query($strSQL);
$i=-1;
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arrResult[$i++] = $row[0]; }
$randKeys = array_rand($arrResult, $intNumberofSites);
$arrOutput = array_intersect_key($randKeys, $arrResult);
}
return $arrOutput;
}
我做了一个简单的10,000次迭代循环,其中我拉了2个随机站点。我关闭并为每个函数打开一个新的浏览器,并在运行之间清除缓存。我进行了三次测试以获得简单的平均值。
注 - 第三种解决方案在拉动少于2个位置时失败,因为如果array_rand函数返回一组或单个结果,则array_rand函数具有不同的输出。我很懒,没有完全实现条件来处理这种情况。
- 1平均:12.38003755秒
- 2平均:12.47702177秒
- 3平均:12.7124153秒
如果只有以往任何时候都为至多500然后整理兰特()是足够快。 – 2009-02-17 21:20:24
同意JPunyon关于预优化和给定最多500条记录,一个不同的解决方案将会变得多快,并且是当前缓慢的函数? – 2009-02-17 21:47:20