2009-02-17 44 views
3

我想从数据库中显示一个随机记录。如果我选择,我希望能够显示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中有空洞。没有大量的流失,但发生的任何流失都需要我们团队的批准,因此可以处理以缓存任何缓存。

感谢您的回复!

+0

如果只有以往任何时候都为至多500然后整理兰特()是足够快。 – 2009-02-17 21:20:24

+0

同意JPunyon关于预优化和给定最多500条记录,一个不同的解决方案将会变得多快,并且是当前缓慢的函数? – 2009-02-17 21:47:20

回答

3

为什么不在你的数据库查询的orderby中使用Rand函数?然后,你不必进入代码中随机等等

喜欢的东西(我不知道这是否是合法的)

Select * 
from site_info 
Order by Rand() 
LIMIT N 

其中N是你想要的记录数。 ..

编辑
你有没有你的代码与查询解决方案?我想你只是在这里预先优化。

+1

他的代码中被注释掉了,标记为低效。 – 2009-02-17 21:15:22

+0

嗯,我不觉得Sheepish ... – 2009-02-17 21:16:35

0
mysql_query("SELECT id FROM site_info WHERE major <> 0 ORDER BY RAND() LIMIT $intNumberofSites") 

编辑 妈,JPunyon是有点快:)

-1

我会简单地使用rand()函数(我假设你正在使用MySQL)...

SELECT id, rand() as rand_idx FROM site_info WHERE major <> 0 ORDER BY rand_idx LIMIT x; 
3

如果你不想用rand()命令来选择。

相反shuffeling的,对结果使用array_rand

$randKeys = array_rand($arrResult, $intNumberofSites); 
$arrOutput = array_intersect_key(array_flip($randKeys), $arrResult); 

编辑:归还钥匙的数组没有新的数组与关键=>值

1

嗯,我不认为ORDER BY RAND ()在只有66行的表中会很慢,但是无论如何你可以看看几个不同的解决方案。

数据是否真的稀疏和/或经常更新(所以ID有很大的差距)?

假设它不是很稀疏,您可以从表中选择最大ID,使用PHP的内置随机函数从1到最大ID之间选择N个不同的数字,然后尝试从这些ID获取行桌子。如果您获取的行数少于您选择的数字,请获取更多随机数并重试,直到获得所需的行数。这可能不是特别快。

如果数据很稀疏,我会设置一个辅助的“id-type”列,确保它是连续的。因此,如果表格中有66行,请确保新列包含值1-66。每当将行添加到表中或从表中移除时,都必须执行一些工作来调整此列中的值。然后使用与上述相同的技术,在PHP中选择随机ID,但不必担心“丢失ID?重试”情况。

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带来第二次机会。

您选择的行数越多,机会就越大。

-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; 
} 
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个随机站点。我关闭并为每个函数打开一个新的浏览器,并在运行之间清除缓存。我进行了三次测试以获得简单的平均值。

注 - 第三种解决方案在拉动少于2个位置时失败,因为如果array_rand函数返回一组或单个结果,则array_rand函数具有不同的输出。我很懒,没有完全实现条件来处理这种情况。

  • 1平均:12.38003755秒
  • 2平均:12.47702177秒
  • 3平均:12.7124153秒