我想从数据库中显示一条随机记录。如果我选择,我希望能够显示X个随机记录。因此,我需要从随机选择的ID列表
中选择前X个记录(除非地球的大小显着增加,否则将永远不会有超过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()有效,但我可以做得更好吗?
MORE UPDATE ID中有漏洞。没有大量的流失,但任何流失都需要得到我们团队的批准,因此可以处理以转储任何缓存。
感谢您的回复!
答案 0 :(得分:3)
为什么不在数据库查询中使用orderby中的Rand函数?那么你不必在代码中进行随机化...
类似的东西(我不知道这是否合法)
Select *
from site_info
Order by Rand()
LIMIT N
其中N是您想要的记录数...
修改强>
您是否已将您的代码与查询解决方案进行了分析?我想你只是在这里进行预优化。
答案 1 :(得分:3)
如果您不想通过rand()选择订单。
而不是改组,在结果上使用array_rand:
$randKeys = array_rand($arrResult, $intNumberofSites);
$arrOutput = array_intersect_key(array_flip($randKeys), $arrResult);
编辑:使用key =&gt;返回键数组而不是新数组值
答案 2 :(得分:1)
好吧,我不认为ORDER BY RAND()在一个只有66行的表中会那么慢,但是你可以考虑一些不同的解决方案。
数据是否真的稀疏和/或经常更新(因此ID中存在很大差距)?
假设它不是很稀疏,你可以从表中选择最大id,使用PHP的内置随机函数来选择1和最大id之间的N个不同数字,然后尝试从中获取带有这些ID的行。表。如果您获得的行数少于您选择的数字,请获取更多随机数并再试一次,直到您拥有所需的行数。这可能也不是特别快。
如果数据稀疏,我会设置一个辅助“id-type”列,确保它是连续的。因此,如果表中有66行,请确保新列包含值1-66。无论何时向表中添加行或从表中删除行,都必须执行一些操作来调整此列中的值。然后使用与上面相同的技术,在PHP中选择随机ID,但您不必担心“缺少ID?重试”的情况。
答案 3 :(得分:1)
以下是我编写和测试的三个函数
我的回答
/***************************************************/
/* 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个随机站点。我为每个函数关闭并打开了一个新浏览器,并清除了运行之间的缓存。我跑了3次试验得到一个简单的平均值。
注意 - 第三个解决方案在拉少于2个站点时失败,因为如果array_rand函数返回一个set或single结果,则它具有不同的输出。我很懒,并没有完全实现条件来处理这种情况。
答案 4 :(得分:0)
mysql_query("SELECT id FROM site_info WHERE major <> 0 ORDER BY RAND() LIMIT $intNumberofSites")
EDIT 该死的,JPunyon有点快:)
答案 5 :(得分:0)
试试这个:
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没有第二次机会。
您选择的行数越多,机会就越大。
答案 6 :(得分:-1)
我只想使用rand()函数(我假设您使用的是MySQL)......
SELECT id, rand() as rand_idx FROM site_info WHERE major <> 0 ORDER BY rand_idx LIMIT x;
答案 7 :(得分:-1)
我和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;
}