2009-02-17 39 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秒