Frage

Was ist eine schnelle Art und Weise eine zufällige Zeile aus einer großen MySQL-Tabelle zu wählen?

Ich arbeite in PHP, aber ich bin daran interessiert, jede Lösung, auch wenn sie in einer anderen Sprache ist.

War es hilfreich?

Lösung

Schnappen Sie alle IDs, ein gelegentliches von ihm holen, und rufen Sie die vollständige Reihe.

Wenn Sie wissen, dass der IDs sequenziell sind ohne Löcher, können Sie einfach den max greifen und eine zufällige ID berechnen.

Wenn es Löcher hier und da aber meist sequenzielle Werte, und Sie kümmern sich nicht um eine leicht schiefe Zufälligkeit, den maximalen Wert greifen, eine ID berechnen, und wählen Sie die erste Zeile mit einer ID gleich oder über einen Sie berechnet. Der Grund für die Schrägstellung ist, dass ids solche Löcher folgenden werden als solche eine höhere Chance, aufgenommen haben, die eine andere ID folgen.

Wenn Sie durch gelegentliches bestellen, Sie gehen eine schreckliche Tisch-Scan auf den Händen haben, und das Wort quick gilt nicht für eine solche Lösung.

Sie das nicht tun, noch sollten Sie durch eine GUID bestellen, es hat das gleiche Problem.

Andere Tipps

wusste, dass ich es musste ein Weg, um es in einer einzigen Abfrage auf einer schnellen Art und Weise zu tun. Und hier ist sie:

Eine schnelle Art und Weise ohne Einbeziehung externen Code, ein dickes Lob an

http://jan.kneschke.de/projects/mysql/order -von-rand /

SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1;

MediaWiki verwendet einen interessanten Trick (für Wikipedias Special: Random-Funktion): Die Tabelle mit den Artikeln hat eine zusätzliche Spalte mit einer Zufallszahl (erzeugt, wenn der Artikel erstellt wird). Um einen zufälligen Artikel zu erhalten, um eine Zufallszahl erzeugen und den Artikel mit dem nächst größeren oder kleinerem bekommen (nicht erinnern, welcher) Wert in der Zufallszahl-Spalte. Mit einem Index, kann dies sehr schnell sein. (Und MediaWiki ist in PHP geschrieben und entwickelt für MySQL.)

Dieser Ansatz kann zu einem Problem führen, wenn die daraus resultierenden Zahlen schlecht verteilt sind; IIRC, dies auf MediaWiki wurde behoben, so dass, wenn Sie es auf diese Weise haben Sie einen Blick auf den Code nehmen sollte, um zu sehen, wie es derzeit gemacht wird (wahrscheinlich regelmäßig regenerieren sie die Zufallszahl Spalte).

Hier ist eine Lösung, die relativ schnell läuft, und es wird eine bessere statistische Verteilung ohne Abhängigkeit von ID-Werten, die angrenzend oder beginnend bei 1.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

Vielleicht könnten Sie so etwas wie:

SELECT * FROM table 
  WHERE id=
    (FLOOR(RAND() * 
           (SELECT COUNT(*) FROM table)
          )
    );

Dies wird vorausgesetzt, Ihre ID-Nummern alle sequenziellen ohne Lücken sind.

Fügen Sie eine Spalte mit einem berechneten Zufallswert auf jede Zeile enthält, und verwendet, die in der Reihenfolge Klausel, nach der Auswahl auf ein Ergebnis zu begrenzen. Das funktioniert schneller als die Tabellenscan hat, die Ursachen ORDER BY RANDOM().

Update: Sie müssen noch einigen zufälligen Wert vor der Erteilung der SELECT Aussage auf Abruf, natürlich berechnen, z

.
SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1

Ein einfacher, aber langsam Weg wäre (gut für kleinere Tabellen)

SELECT * from TABLE order by RAND() LIMIT 1

In Pseudo-Code:

sql "select id from table"
store result in list
n = random(size of list)
sql "select * from table where id=" + list[n]

Dies setzt voraus, dass id ist ein einzigartiger (primärer) Schlüssel.

Es gibt eine andere Art und Weise Zufallsreihen zu erzeugen mit nur einer Abfrage und ohne Auftrag von rand (). Es geht um Benutzerdefinierte Variablen. Siehe wie zufällige Zeilen aus einer Tabelle erzeugen

Um zufällige Zeilen aus einer Tabelle zu finden, verwenden Sie keine ORDER BY RAND (), weil es MySQL erzwingt eine vollständige Datei Art zu tun und erst dann die Grenze Zeilen Nummer erforderlich abzurufen. Um diese vollständige Datei Art zu vermeiden, verwenden Sie die Funktion RAND () nur auf der Where-Klausel. Er stoppt, sobald es auf die erforderliche Anzahl von Zeilen erreicht. Sehen http://www.rndblog.com/how-to- wählen Zufalls-Zeilen-in-mysql /

, wenn Sie keine Zeile in dieser Tabelle löschen, der effizienteste Weg ist:

(wenn Sie die mininum id wissen einfach überspringen)

SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1

$randId=mt_rand((int)$row['minId'], (int)$row['maxId']);

SELECT id,name,... FROM table WHERE id=$randId LIMIT 1

Für mehr zufälligen Zeilen aus einer bestimmten Tabelle auswählen (sagen ‚Worten‘), unser Team kam mit dieser Schönheit auf:

SELECT * FROM
`words` AS r1 JOIN 
(SELECT  MAX(`WordID`) as wid_c FROM `words`) as tmp1
WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n

Die klassische "SELECT id FROM table ORDER BY RAND () LIMIT 1" ist eigentlich OK.

Sehen Sie den nachfolgenden Auszug aus dem MySQL-Handbuch:

Wenn Sie LIMIT row_count mit ORDER BY verwenden, beendet MySQL die Sortierung, sobald sie die ersten row_count Reihen des sortierten Ergebnisses gefunden haben, anstatt das gesamte Ergebnis sortieren.

Mit einer Bestellung yo eine Scan-Tabelle tun. Seine besten, wenn Sie tun, um eine SELECT COUNT (*) und später eine zufällige Zeile = rownum zwischen 0 und der letzten Registrierung erhalten

Hier finden Sie aktuelle diesen Link von Jan Kneschke oder diese sO beantworten als sie beide diskutieren die gleiche Frage. Die SO Antwort geht über verschiedene Optionen auch und hat einige gute Vorschläge je nach Ihren Bedürfnissen. Jan geht über die verschiedenen Optionen und die Leistungsmerkmale der einzelnen. Er endet mit der folgenden für die optimierten Verfahren auf, mit dem zu tun, dies innerhalb einer MySQL wählen:

SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1;

HTH,

-Dipin

Ich bin ein bisschen neu zu SQL, aber wie wäre es eine Zufallszahl in PHP zu erzeugen und mit

SELECT * FROM the_table WHERE primary_key >= $randNr

das Problem mit Löchern in der Tabelle nicht lösen.

Aber hier ist eine Torsion auf lassevks Vorschlag:

SELECT primary_key FROM the_table

Verwenden mysql_num_rows () in PHP erstellen eine Zufallszahl basierend auf dem obigen Ergebnis:

SELECT * FROM the_table WHERE primary_key = rand_number

Auf einer Seite zur Kenntnis, wie langsam ist SELECT * FROM the_table:
Erstellen einer Zufallszahl basierend auf mysql_num_rows() und dann den Datenzeiger zu diesem Punkt mysql_data_seek() bewegt. Wie langsam wird dies auf großen Tischen wird mit einer Million Zeilen sagen?

Ich lief in das Problem, wo meine IDs wurden nicht sequentiell. Was ich kam mit dieser.

SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1

Die zurückgegebenen Zeilen sind etwa 5, aber ich beschränken es auf 1.

Wenn Sie eine weitere hinzufügen möchten WHERE-Klausel es ein wenig interessanter wird. Sagen Sie bitte für Produkte auf Rabatt suchen möchten.

SELECT * FROM products WHERE RAND()<=(100/(SELECT COUNT(*) FROM pt_products)) AND discount<.2 LIMIT 1

Was müssen Sie tun, ist sicherzustellen, dass Sie genug Ergebnis zurückkehren, weshalb ich es auf 100 festgelegt haben Mit einer WHERE-Aktionen <0,2 Klausel in der Unterabfrage war 10-fach langsamer, so dass es besser ist, mehr Ergebnisse und Grenze zurückzukehren .

Ich sehe hier eine Menge Lösung. Ein oder zwei scheint ok, aber andere Lösungen haben einige Einschränkungen. Aber die folgende Lösung wird für alle Situation arbeitet

select a.* from random_data a, (select max(id)*rand() randid  from random_data) b
     where a.id >= b.randid limit 1;

Hier id, müssen nicht sequentiell sein. Es könnte jeder Primärschlüssel / einzigartig / Autoinkrement Spalte sein. Bitte beachten Sie die folgenden schnellster Weg, um eine zufällige Zeile aus einer großen MySQL-Tabelle , um

Danke Zillur - www.techinfobest.com

Mit der folgenden Abfrage, um die zufällige Reihe bekommen

SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails 
GROUP BY usr_fk_id 
ORDER BY cnt ASC  
LIMIT 1

In meinem Fall meine Tabelle eine ID als Primärschlüssel hat, Autoinkrement ohne Lücken, so kann ich COUNT(*) oder MAX(id) verwenden, um die Anzahl der Zeilen zu erhalten.

Ich habe dieses Skript den schnellsten Betrieb zu testen:

logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();

Die Ergebnisse sind:

  • Count: 36.8418693542479 ms
  • Max: 0.241041183472 ms
  • Auftrag : 0.216960906982 ms

Antwort mit der Auftragsmethode:

SELECT FLOOR(RAND() * (
    SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 1

...
SELECT * FROM tbl WHERE id = $result;

Ich habe dies und der Auftrag verwendet wurde getan die Referenz von hier

SELECT * FROM myTable WHERE RAND()<(SELECT ((30/COUNT(*))*10) FROM myTable) ORDER BY RAND() LIMIT 30;

Erstellen Sie eine Funktion diese höchstwahrscheinlich die beste Antwort zu tun, und die meist schnellste Antwort hier!

Pros -. Funktioniert auch mit Lücken und extrem schnell

<?

$sqlConnect = mysqli_connect('localhost','username','password','database');

function rando($data,$find,$max = '0'){
   global $sqlConnect; // Set as mysqli connection variable, fetches variable outside of function set as GLOBAL
   if($data == 's1'){
     $query = mysqli_query($sqlConnect, "SELECT * FROM `yourtable` ORDER BY `id` DESC LIMIT {$find},1");

     $fetched_data = mysqli_fetch_assoc($query);
      if(mysqli_num_rows($fetched_data>0){
       return $fetch_$data;
      }else{
       rando('','',$max); // Start Over the results returned nothing
      }
   }else{
     if($max != '0'){
        $irand = rand(0,$max); 
        rando('s1',$irand,$max); // Start rando with new random ID to fetch
     }else{

        $query = mysqli_query($sqlConnect, "SELECT `id` FROM `yourtable` ORDER BY `id` DESC LIMIT 0,1");
        $fetched_data = mysqli_fetch_assoc($query);
        $max = $fetched_data['id'];
        $irand = rand(1,$max);
        rando('s1',$irand,$max); // Runs rando against the random ID we have selected if data exist will return
     }
   }
 }

 $your_data = rando(); // Returns listing data for a random entry as a ASSOC ARRAY
?>

Bitte beachten Sie diesen Code als nicht getestet, sondern ist ein Arbeitskonzept zufällige Einträge zurückzukehren, auch mit Lücken .. Solange die Lücken nicht riesig genug sind, um eine Ladezeit Problem zu verursachen.

quick and dirty-Methode:

SET @COUNTER=SELECT COUNT(*) FROM your_table;

SELECT PrimaryKey
FROM your_table
LIMIT 1 OFFSET (RAND() * @COUNTER);

Die Komplexität der ersten Abfrage ist O (1) für MyISAM-Tabellen.

Die zweite Abfrage begleitet eine Tabelle Scan. Komplexität = O (n)

Schmutzige und schnelle Methode:

eine separate Tabelle für diesen Zweck hält nur. Sie sollten auch die gleichen Zeilen in dieser Tabelle einfügen, wenn auf die ursprüngliche Tabelle einfügen. Annahme:. Kein DELETEs

CREATE TABLE Aux(
  MyPK INT AUTO_INCREMENT,
  PrimaryKey INT
);

SET @MaxPK = (SELECT MAX(MyPK) FROM Aux);
SET @RandPK = CAST(RANDOM() * @MaxPK, INT)
SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK = @RandPK);

Wenn DELETEs erlaubt,

SET @delta = CAST(@RandPK/10, INT);

SET @PrimaryKey = (SELECT PrimaryKey
                   FROM Aux
                   WHERE MyPK BETWEEN @RandPK - @delta AND @RandPK + @delta
                   LIMIT 1);

Die Gesamtkomplexität O (1).

SELECT DISTINCT * FROM yourTable WHERE 4 = 4 LIMIT 1;

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top