MySQL rastgele kayıtların değişken sayısını seçin

7 Cevap php

Ben veritabanından rastgele kayıt göstermek istiyorum. Ben seçersem rastgele kayıtların X sayısını göstermek mümkün olmak istiyorum. Bu nedenle kimlikleri rastgele seçilen bir listeden üst X kayıtları seçmek gerekir

(Toprak dramatik boyutu artar sürece, seçim dahil 500'den fazla kayıt var olmayacak. Şu anda 66 possibles vardır.)

Bu fonksiyon çalışır, ama nasıl daha iyi yapabilirim?

/***************************************************/
/* 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;
    }

UPDATE QUESTION: I know about the ORDER BY RAND(), I just don't want to use it because there are rumors it isn't the best at scaling and performance. I am being overly critical of my code. What I have works, ORDER BY RAND() works, but can I make it better?

MORE UPDATE There are holes in the IDs. There is not a ton of churn, but any churn that happens needs to be approved by our team, and therefore could handled to dump any caching.

Cevaplar için teşekkürler!

7 Cevap

Neden veritabanı sorgu bir OrderBy yılında Rand Fonksiyonu kullanmaz? Sonra kod vb randomizing içine almak zorunda değilsiniz ...

Gibi bir şey (bu yasal olup olmadığını bilmiyorum)

Select *
from site_info
Order by Rand()
LIMIT N

N istediğiniz kayıt sayısı olduğu ...

EDIT
Have you profiled your code vs. the query solution? I think you're just pre-optimizing here.

Eğer rand tarafından sipariş ile seçmek istemiyorsanız ().

Bunun yerine shuffeling arasında array_rand sonucu kullanın:

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

edit: tuşları return array anahtar => değer ile değil, yeni dizi

Eh, ben RAND (BY ki ORDER) sadece 66 satır ile bir tabloyla yavaş olacağını sanmıyorum, ama yine de bir kaç farklı çözümler içine bakabilirsiniz.

Veri gerçekten seyrek ve / veya sık sık güncellenen (çok büyük boşluklar kimlikleri vardır) mı?

Çok seyrek değil varsayarsak, sen tablodan maksimum id seçin kullanabilirsiniz PHP'nin yerleşik rasgele fonksiyonu 1 ve max id arasındaki N belirgin numaralarını almak ve sonra masadan bu kimlikleri ile satır getirmek için teşebbüs etmek. Eğer numaralarını aldım daha az satır geri almak Eğer gerekli satır sayısını sahip olana kadar, daha rastgele sayılar almak ve tekrar deneyin. Bu da özellikle hızlı olmayabilir.

Veriler çok azdır, ben emin sıralı yapmak ikincil bir "id-tipi" sütunu kuracak. Tabloda 66 satır varsa Yani, yeni bir sütun değerleri 1-66 içerdiğinden emin olun. Satır eklenecek veya tablodan kaldırılır zaman, bu sütundaki değerleri ayarlamak için bazı işler yapmak zorunda olacak. Sonra PHP rastgele kimlikleri toplama, yukarıdaki gibi aynı tekniği kullanın, ancak endişelenmenize gerek yok "eksik kimliği? Yeniden" olgusu.

İşte ben yazdım ve test üç fonksiyonları

Benim cevabım

/***************************************************/
/* 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 ve diğerleri

/***************************************************/
/* 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;
    }

Yaratıcı bir çözüm toplantısı ile OIS sorumun niyetinde.

/***************************************************/
/* 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;
    }

Ben 2 rastgele siteleri çekti 10.000 yineleme basit bir döngü yaptım. Ben kapalı ve her bir fonksiyon için yeni bir tarayıcı açtı ve kaçak arasındaki önbelleğe alınmış temizledi. Ben basit bir ortalama almak için testi 3 kez koştu.

NOT - Bir dizi ya da tek bir sonuç döndürürse, üçüncü çözüm array_rand fonksiyonu olarak en az 2 siteleri çekerek başarısız farklı çıkışı vardır. Ben tembel var ve tamamen bu davayı ele koşullu uygulamak vermedi.

  • 1 ortalama: 12,38003755 saniye
  • 2 ortalama: 12,47702177 saniye
  • 3 ortalama: 12,7124153 saniye

Bu deneyin:

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

Bu azalan, dizin kullanarak her tekrarında rasgele bir kimlik seçecektir.

Eğer cevapsız id yıllara ikinci bir şans verir gibi, istediği az sonuç almak bu olsa hafif bir şans, var.

Seçtiğiniz satır daha yüzde daha büyük şans.

Ben sadece rand () function (Ben MySQL kullanıyorsanız varsayıyorum) kullanmak istiyorsunuz ...

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

Ben JPunyon beraberim. Kullan ORDER BY RAND() LIMIT $N. Sana $arrResult olan ve MySQL RAND () fonksiyonu kullanarak daha çok (kullanılmayan) girdilerini sürüyerek gelen büyük bir performans isabet alırsınız düşünüyorum.

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;
}