Ja, wenn Sie potenziell große Lücken in den IDs haben, ist die Wahrscheinlichkeit, dass Ihre niedrigsten IDs zufällig ausgewählt werden, viel geringer als Ihre hohen IDs. Tatsächlich ist die Wahrscheinlichkeit, dass die erste ID nach der größten Lücke ausgewählt wird, tatsächlich die höchste. Daher ist dies per Definition nicht zufällig.
Lukecodes
6
Wie bekommt man 10 verschiedene zufällige Zeilen? Müssen Sie das Limit auf 10 setzen und dann 10 Mal mit wiederholen mysqli_fetch_assoc($result)? Oder sind diese 10 Ergebnisse nicht unbedingt unterscheidbar?
Adam
12
Zufällig erfordert meiner Meinung nach die gleiche Chance für jedes Ergebnis. ;)
lukeocodes
4
Der vollständige Artikel befasst sich mit Problemen wie ungleichen Verteilungen und wiederholten Ergebnissen.
Bradd Szonye
1
Insbesondere wenn Sie zu Beginn Ihrer IDs eine Lücke haben, wird die erste (min / max-min) der Zeit ausgewählt. In diesem Fall ist eine einfache Änderung MAX () - MIN () * RAND + MIN (), was nicht zu langsam ist.
Mateusz - Proof pls, SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10dauert 0,0010, ohne LIMIT 10 dauerte es 0,0012 (in dieser Tabelle 3500 Wörter).
Arthur Kushman
26
@zeusakm 3500 Wörter sind nicht so viel; Das Problem ist, dass es über einen bestimmten Punkt hinaus explodiert, da MySQL nach dem Lesen jedes einzelnen Datensatzes ALLE Datensätze sortieren muss. Sobald diese Operation auf die Festplatte trifft, können Sie den Unterschied spüren.
Ja͢ck
16
Ich möchte mich nicht wiederholen, aber das ist wieder ein vollständiger Tabellenscan. Bei großen Tabellen ist dies sehr zeit- und speicherintensiv und kann dazu führen, dass eine temporäre Tabelle auf der Festplatte erstellt und ausgeführt wird, was sehr langsam ist.
Matt
10
Als ich 2010 ein Interview mit Facebook führte, fragten sie mich, wie ich in einer Lesung einen zufälligen Datensatz aus einer riesigen Datei unbekannter Größe auswählen könne. Sobald Sie eine Idee haben, können Sie diese leicht verallgemeinern, um mehrere Datensätze auszuwählen. Also ja, das Sortieren der gesamten Datei ist lächerlich. Gleichzeitig ist es sehr praktisch. Ich habe gerade diesen Ansatz verwendet, um 10 zufällige Zeilen aus einer Tabelle mit mehr als 1.000.000 Zeilen auszuwählen. Klar, ich musste ein bisschen warten; aber ich wollte nur eine Vorstellung davon bekommen, wie typische Zeilen in dieser Tabelle aussehen ...
osa
27
Einfache Abfrage, die eine hervorragende Leistung aufweist und mit Lücken arbeitet :
SELECT*FROM tbl AS t1 JOIN(SELECT id FROM tbl ORDERBY RAND() LIMIT 10)as t2 ON t1.id=t2.id
Diese Abfrage für eine 200K-Tabelle dauert 0,08 Sekunden und die normale Version (SELECT * FROM tbl ORDER BY RAND () LIMIT 10) dauert 0,35 Sekunden auf meinem Computer .
Dies ist schnell, da in der Sortierphase nur die indizierte ID-Spalte verwendet wird. Sie können dieses Verhalten in der Erklärung sehen:
SELECT * FROM tbl ORDER BY RAND () LIMIT 10:
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND () LIMIT 10) als t2 ON t1.id = t2.id.
Entschuldigung, ich habe getestet! langsame Leistung bei 600.000 Datensätzen.
Dylan B
@ DylanB Ich habe die Antwort mit einem Test aktualisiert.
Ali
17
Ich erhalte schnelle Abfragen (ca. 0,5 Sekunden) mit einer langsamen CPU und wähle 10 zufällige Zeilen in einer nicht zwischengespeicherten 2-GB-Größe der MySQL-Datenbank mit 400 KB aus. Siehe hier meinen Code: Schnelle Auswahl von zufälligen Zeilen in MySQL
<?php
$time= microtime_float();$sql='SELECT COUNT(*) FROM pages';$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);$sql="SELECT id FROM pages WHERE RAND()*$num_records<20
ORDER BY RAND() LIMIT 0,10";$rquery= BD_Ejecutar($sql);while(list($id)=mysql_fetch_row($rquery)){if($id_in)$id_in.=",$id";else$id_in="$id";}
mysql_free_result($rquery);$sql="SELECT id,url FROM pages WHERE id IN($id_in)";$rquery= BD_Ejecutar($sql);while(list($id,$url)=mysql_fetch_row($rquery)){
logger("$id, $url",1);}
mysql_free_result($rquery);$time= microtime_float()-$time;
logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);?>
Angesichts meiner über 14 Millionen Datensätze Tabelle ist dies so langsam wieORDER BY RAND()
Fabrizio
5
@snippetsofcode In Ihrem Fall - 400k Zeilen können Sie einfach "ORDER BY rand ()" verwenden. Ihr Trick mit 3 Abfragen ist nutzlos. Sie können es umschreiben wie "SELECT ID, URL FROM Seiten WHERE ID IN (SELECT ID FROM Seiten ORDER BY Rand () LIMIT 10)"
Roman Podlinov
4
Ihre Technik führt immer noch einen Tabellenscan durch. Verwenden Sie FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';, um es zu sehen.
Rick James
4
Versuchen Sie auch, diese Abfrage auf einer Webseite mit 200 Anforderungen / s auszuführen. Parallelität wird dich töten.
Marki555
Der Vorteil von @RomanPodlinov gegenüber der Ebene ORDER BY RAND()besteht darin, dass nur die IDs (nicht die vollständigen Zeilen) sortiert werden, sodass die temporäre Tabelle kleiner ist, aber dennoch alle sortiert werden muss.
Manchmal wird die LANGSAME akzeptiert, wenn ich sie
Die Indizierung sollte auf die Tabelle angewendet werden, wenn sie groß ist.
Muhammad Azeem
1
Indizierung hilft hier nicht weiter. Indizes sind für ganz bestimmte Dinge hilfreich, und diese Abfrage gehört nicht dazu.
Andrew
13
Aus dem Buch:
Wählen Sie eine zufällige Zeile mit einem Versatz
Eine weitere Technik, die Probleme in den vorhergehenden Alternativen vermeidet, besteht darin, die Zeilen im Datensatz zu zählen und eine Zufallszahl zwischen 0 und der Anzahl zurückzugeben. Verwenden Sie diese Nummer dann als Offset, wenn Sie den Datensatz abfragen
Verwenden Sie diese Lösung, wenn Sie keine zusammenhängenden Schlüsselwerte annehmen können und sicherstellen müssen, dass jede Zeile eine gleichmäßige Chance hat, ausgewählt zu werden.
Das hilft einigen für MyISAM, aber nicht für InnoDB (vorausgesetzt, id ist das Clustered PRIMARY KEY).
Rick James
7
Wenn Ihre Schlüssel keine Lücken aufweisen und alle numerisch sind, können Sie Zufallszahlen berechnen und diese Zeilen auswählen. Dies wird aber wahrscheinlich nicht der Fall sein.
Dies stellt im Grunde sicher, dass Sie eine Zufallszahl im Bereich Ihrer Tasten erhalten und dann die nächstbeste auswählen, die größer ist. Sie müssen dies 10 Mal tun.
Dies ist jedoch NICHT wirklich zufällig, da Ihre Schlüssel höchstwahrscheinlich nicht gleichmäßig verteilt werden.
Es ist wirklich ein großes Problem und nicht einfach zu lösen, um alle Anforderungen zu erfüllen. Rand () von MySQL ist das Beste, was Sie bekommen können, wenn Sie wirklich 10 zufällige Zeilen wollen.
Können Sie uns etwas mehr erklären, damit ich Ihnen eine gute Lösung geben kann?
Zum Beispiel hatte ein Unternehmen, mit dem ich zusammengearbeitet habe, eine Lösung, bei der es extrem schnell um absolute Zufälligkeit ging. Am Ende wurde die Datenbank mit Zufallswerten gefüllt, die absteigend ausgewählt und anschließend wieder auf andere Zufallswerte gesetzt wurden.
Wenn Sie kaum jemals aktualisieren, können Sie auch eine inkrementelle ID eingeben, damit Sie keine Lücken haben und vor der Auswahl nur zufällige Schlüssel berechnen können ... Dies hängt vom Anwendungsfall ab!
Hallo Joe. In diesem speziellen Fall sollten die Schlüssel keine Lücken aufweisen, dies kann sich jedoch im Laufe der Zeit ändern. Und während Ihre Antwort funktioniert, werden die zufälligen 10 Zeilen (vorausgesetzt, ich schreibe Limit 10) aufeinanderfolgend generiert, und ich wollte sozusagen mehr Zufälligkeit. :) Vielen Dank.
Francisc
Wenn Sie 10 benötigen, verwenden Sie eine Art Vereinigung, um 10 eindeutige Zeilen zu generieren.
Johno
tahts was ich gesagt habe. Sie müssen das 10 Mal ausführen. Das Kombinieren mit Wition Union ist eine Möglichkeit, es in einer Abfrage zusammenzufassen. siehe meinen Nachtrag vor 2 Minuten.
The Surrican
1
@ TheSurrican, Diese Lösung sieht cool aus, ist aber sehr fehlerhaft . Versuchen Sie, nur eine sehr große einzufügen, Idund alle Ihre zufälligen Abfragen geben Ihnen diese zurück Id.
Pacerier
1
FLOOR(RAND()*MAX(id))ist voreingenommen in Richtung der Rückgabe größerer IDs.
Rick James
3
Ich brauchte eine Abfrage, um eine große Anzahl zufälliger Zeilen aus einer ziemlich großen Tabelle zurückzugeben. Das habe ich mir ausgedacht. Erhalten Sie zuerst die maximale Datensatz-ID:
SELECT MAX(id)FROM table_name;
Ersetzen Sie diesen Wert dann durch:
SELECT*FROM table_name WHERE id > FLOOR(RAND()* max) LIMIT n;
Dabei ist max die maximale Datensatz-ID in der Tabelle und n die Anzahl der Zeilen, die Sie in Ihrer Ergebnismenge haben möchten. Die Annahme ist, dass es keine Lücken in den Datensatz-IDs gibt, obwohl ich bezweifle, dass dies das Ergebnis beeinflussen würde, wenn es solche gäbe (habe es aber nicht versucht). Ich habe diese gespeicherte Prozedur auch allgemeiner erstellt. Übergeben Sie den Tabellennamen und die Anzahl der zurückzugebenden Zeilen. Ich verwende MySQL 5.5.38 unter Windows 2008, 32 GB, Dual 3 GHz E5450 und in einer Tabelle mit 17.361.264 Zeilen ist es mit ~ 0,03 Sekunden / ~ 11 Sekunden ziemlich konsistent, um 1.000.000 Zeilen zurückzugeben. (Die Zeiten stammen aus MySQL Workbench 6.1. Sie können in der zweiten select-Anweisung auch CEIL anstelle von FLOOR verwenden, je nach Ihren Vorlieben.)
Ich möchte eine andere Möglichkeit der Beschleunigung aufzeigen - das Caching . Überlegen Sie, warum Sie zufällige Zeilen benötigen. Wahrscheinlich möchten Sie einen zufälligen Beitrag oder eine zufällige Anzeige auf einer Website anzeigen. Wenn Sie 100 Anforderungen / s erhalten, ist es wirklich erforderlich, dass jeder Besucher zufällige Zeilen erhält? Normalerweise ist es völlig in Ordnung, diese X zufälligen Zeilen 1 Sekunde (oder sogar 10 Sekunden) zwischenzuspeichern. Es spielt keine Rolle, ob 100 eindeutige Besucher in derselben Sekunde dieselben zufälligen Beiträge erhalten, da in der nächsten Sekunde weitere 100 Besucher unterschiedliche Beiträge erhalten.
Wenn Sie dieses Caching verwenden, können Sie auch einige der langsameren Lösungen zum Abrufen der Zufallsdaten verwenden, da diese unabhängig von Ihren Anforderungen nur einmal pro Sekunde von MySQL abgerufen werden.
Ich habe die Antwort von @Riedsio verbessert. Dies ist die effizienteste Abfrage, die ich für eine große, gleichmäßig verteilte Tabelle mit Lücken finden kann (getestet, um 1000 zufällige Zeilen aus einer Tabelle mit> 2,6B Zeilen zu erhalten).
(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max :=(SELECT MAX(id)FROMtable))+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)
Lassen Sie mich auspacken, was los ist.
@max := (SELECT MAX(id) FROM table)
Ich berechne und speichere die max. Bei sehr großen Tabellen entsteht ein geringer Aufwand für die Berechnung MAX(id)jedes Mal, wenn Sie eine Zeile benötigen
SELECT FLOOR(rand() * @max) + 1 as rand)
Ruft eine zufällige ID ab
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
Dies füllt die Lücken. Wenn Sie zufällig eine Zahl in den Lücken auswählen, wird grundsätzlich nur die nächste ID ausgewählt. Unter der Annahme, dass die Lücken gleichmäßig verteilt sind, sollte dies kein Problem sein.
Durch die Vereinigung können Sie alles in eine Abfrage einpassen, sodass Sie nicht mehrere Abfragen ausführen müssen. Sie können damit auch den Aufwand für die Berechnung sparen MAX(id). Abhängig von Ihrer Anwendung kann dies sehr oder sehr wenig bedeuten.
Beachten Sie, dass dadurch nur die IDs und in zufälliger Reihenfolge abgerufen werden. Wenn Sie etwas Fortgeschritteneres tun möchten, empfehle ich Ihnen Folgendes:
SELECT t.id, t.name -- etc, etcFROMtable t
INNERJOIN((SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max :=(SELECT MAX(id)FROMtable))+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)UNION(SELECT id FROMtableINNERJOIN(SELECT FLOOR(RAND()*@max)+1as rand) r on id > rand LIMIT 1)) x ON x.id = t.id
ORDERBY t.id
Ich brauche 30 zufällige Datensätze, also sollte ich ändern , LIMIT 1um LIMIT 30in Abfrage überall
Hassaan
@ Hassaan sollten Sie nicht, dass das Ändern LIMIT 1zu LIMIT 3030 Datensätze in einer Reihe von einem zufälligen Punkt in der Tabelle erhalten würde. Sie sollten stattdessen 30 Kopien des (SELECT id FROM ....Teils in der Mitte haben.
Hans Z
Ich habe es versucht, aber es scheint nicht effizienter zu sein als zu Riedsioantworten. Ich habe mit 500 pro Sekunde Treffer auf die Seite mit PHP 7.0.22 und MariaDB auf Centos 7 versucht. Mit der RiedsioAntwort habe ich mehr als 500 zusätzliche erfolgreiche Antworten erhalten als Ihre Antwort.
Hassaan
1
Die Antwort von @Hassaan riedsio ergibt 1 Zeile, diese gibt Ihnen n Zeilen und reduziert den E / A-Overhead für die Abfrage. Möglicherweise können Sie Zeilen schneller abrufen, aber Ihr System wird stärker belastet.
DROP TEMPORARY TABLEIFEXISTS rands;CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt <1THEN
LEAVE loop_me;ENDIF;INSERTINTO rands
SELECT r1.id
FROM random AS r1 JOIN(SELECT(RAND()*(SELECT MAX(id)FROM random))AS id)AS r2
WHERE r1.id >= r2.id
ORDERBY r1.id ASC
LIMIT 1;SET cnt = cnt -1;END LOOP loop_me;
In dem Artikel löst er das Problem von Lücken in IDs, die nicht so zufällige Ergebnisse verursachen, indem er eine Tabelle verwaltet (unter Verwendung von Triggern usw. ... siehe Artikel); Ich löse das Problem, indem ich der Tabelle eine weitere Spalte hinzufüge, die mit zusammenhängenden Zahlen gefüllt ist, beginnend mit 1 (hinzufüge Bearbeiten: Diese Spalte wird der temporären Tabelle hinzugefügt, die zur Laufzeit von der Unterabfrage erstellt wurde, wirkt sich nicht auf Ihre permanente Tabelle aus):
DROP TEMPORARY TABLEIFEXISTS rands;CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt <1THEN
LEAVE loop_me;ENDIF;SET@no_gaps_id :=0;INSERTINTO rands
SELECT r1.id
FROM(SELECT id,@no_gaps_id :=@no_gaps_id +1AS no_gaps_id FROM random)AS r1 JOIN(SELECT(RAND()*(SELECT COUNT(*)FROM random))AS id)AS r2
WHERE r1.no_gaps_id >= r2.id
ORDERBY r1.no_gaps_id ASC
LIMIT 1;SET cnt = cnt -1;END LOOP loop_me;
In dem Artikel kann ich sehen, dass er große Anstrengungen unternommen hat, um den Code zu optimieren. Ich habe keine Ahnung, ob / wie sehr sich meine Änderungen auf die Leistung auswirken, aber es funktioniert sehr gut für mich.
"Ich habe keine Ahnung, ob / wie sehr sich meine Änderungen auf die Leistung auswirken" - ziemlich viel. Für die @no_gaps_idkein Index verwendet werden kann, so dass , wenn man sich anschaut , EXPLAINfür Ihre Anfrage, Sie haben Using filesortund Using where(ohne Index) für die Unterabfragen, im Gegensatz zu der ursprünglichen Abfrage.
Fabian Schmengler
2
Hier ist ein Game Changer, der für viele hilfreich sein kann.
Ich habe eine Tabelle mit 200.000 Zeilen und sequentiellen IDs. Ich musste N zufällige Zeilen auswählen. Daher habe ich mich dafür entschieden, zufällige Werte basierend auf der größten ID in der Tabelle zu generieren. Ich habe dieses Skript erstellt, um herauszufinden, welche Operation die schnellste ist:
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:
Anzahl: 36.8418693542479ms
Max: 0.241041183472ms
Reihenfolge: 0.216960906982ms
Basierend auf diesen Ergebnissen ist order desc die schnellste Operation, um die maximale ID zu erhalten.
Hier ist meine Antwort auf die Frage:
SELECT GROUP_CONCAT(n SEPARATOR ',') g FROM(SELECT FLOOR(RAND()*(SELECT id FROM tbl ORDERBY id DESC LIMIT 1)) n FROM tbl LIMIT 10) a
...SELECT*FROM tbl WHERE id IN($result);
Zu Ihrer Information: Um 10 zufällige Zeilen aus einer 200k-Tabelle zu erhalten, habe ich 1,78 ms gebraucht (einschließlich aller Operationen auf der PHP-Seite).
Ich habe über die gleiche Lösung nachgedacht, bitte sagen Sie mir, ist sie schneller als die andere Methode?
G. Adnane
@ G.Adnane ist nicht schneller oder langsamer als die akzeptierte Antwort, aber die akzeptierte Antwort setzt eine gleichmäßige Verteilung der IDs voraus. Ich kann mir kein Szenario vorstellen, in dem dies garantiert werden kann. Diese Lösung befindet sich in O (1), wobei sich die Lösung SELECT column FROM table ORDER BY RAND() LIMIT 10in O (nlog (n)) befindet. Ja, dies ist die schnellste Lösung und funktioniert für jede Verteilung von IDs.
Adam
Nein, da es in dem Link, der für die akzeptierte Lösung gepostet wurde, andere Methoden gibt. Ich möchte wissen, ob diese Lösung schneller ist als die anderen. Auf andere Weise können wir versuchen, eine andere zu finden. Deshalb frage ich auf jeden Fall +1 für deine Antwort. Ich benutzte das gleiche
G. Adnane
Es gibt einen Fall, in dem Sie x Zeilen erhalten möchten, der Versatz jedoch bis zum Ende der Tabelle reicht, wodurch <x Zeilen oder nur 1 Zeile zurückgegeben werden. Ich habe Ihre Antwort nicht gesehen, bevor ich meine gepostet habe, aber ich habe sie hier klarer gemacht. stackoverflow.com/a/59981772/10387008
ZOLDIK
@ZOLDIK es scheint, dass Sie die ersten 10 Zeilen nach dem Versatz auswählen x. Ich würde argumentieren, dass dies keine zufällige Generation von 10 Zeilen ist. In meiner Antwort müssen Sie die Abfrage in Schritt drei zehnmal ausführen, dh man erhält nur eine Zeile pro Ausführung und muss sich keine Sorgen machen, wenn der Offset am Ende der Tabelle steht.
Adam
1
Wenn Sie nur eine Leseanforderung haben
Kombinieren Sie die Antwort von @redsio mit einer temporären Tabelle (600K sind nicht so viel):
DROP TEMPORARY TABLEIFEXISTS tmp_randorder;CREATETABLE tmp_randorder (id int(11)notnull auto_increment primarykey, data_id int(11));INSERTINTO tmp_randorder (data_id)select id from datatable;
Und dann nimm eine Version von @redsios Antwort:
SELECT dt.*FROM(SELECT(RAND()*(SELECT MAX(id)FROM tmp_randorder))AS id)AS rnd
INNERJOIN tmp_randorder rndo on rndo.id between rnd.id -10and rnd.id +10INNERJOIN datatable AS dt on dt.id = rndo.data_id
ORDERBY abs(rndo.id - rnd.id)
LIMIT 1;
Wenn der Tisch groß ist, können Sie den ersten Teil sieben:
INSERTINTO tmp_randorder (data_id)select id from datatable where rand()<0.01;
Wenn Sie viele Leseanfragen haben
Version: Sie könnten die Tabelle behalten tmp_randorder persistent halten und als datatable_idlist bezeichnen. Erstellen Sie diese Tabelle in bestimmten Intervallen (Tag, Stunde) neu, da sie auch Löcher bekommt. Wenn Ihr Tisch wirklich groß wird, können Sie auch Löcher nachfüllen
Wählen Sie l.data_id als Ganzes aus der Liste datatable_id aus. l left join datatable dt on dt.id = l.data_id wobei dt.id null ist.
Version: Geben Sie Ihrem Dataset eine random_sortorder-Spalte entweder direkt in datatable oder in einer persistenten zusätzlichen Tabelle datatable_sortorder. Indizieren Sie diese Spalte. Generieren Sie einen Zufallswert in Ihrer Anwendung (ich werde es nennen $rand).
select l.*from datatable l
orderby abs(random_sortorder -$rand)desc
limit 1;
Diese Lösung unterscheidet die 'Kantenzeilen' mit der höchsten und der niedrigsten random_sortorder, also ordnen Sie sie in Intervallen (einmal am Tag) neu an.
Eine andere einfache Lösung wäre, die Zeilen zu ordnen und eine davon zufällig abzurufen. Mit dieser Lösung müssen Sie keine 'Id'-basierte Spalte in der Tabelle haben.
SELECT d.*FROM(SELECT t.*,@rownum :=@rownum +1AS rank
FROM mytable AS t,(SELECT@rownum :=0)AS r,(SELECT@cnt :=(SELECT RAND()*(SELECT COUNT(*)FROM mytable)))AS n
) d WHERE rank >=@cnt LIMIT 10;
Sie können den Grenzwert nach Bedarf ändern, um auf so viele Zeilen zuzugreifen, wie Sie möchten. Dies sind jedoch meistens aufeinanderfolgende Werte.
Wenn Sie jedoch keine aufeinanderfolgenden Zufallswerte möchten, können Sie eine größere Stichprobe abrufen und zufällig auswählen. etwas wie ...
SELECT*FROM(SELECT d.*FROM(SELECT c.*,@rownum :=@rownum +1AS rank
FROM buildbrain.`commits`AS c,(SELECT@rownum :=0)AS r,(SELECT@cnt :=(SELECT RAND()*(SELECT COUNT(*)FROM buildbrain.`commits`)))AS rnd
) d
WHERE rank >=@cnt LIMIT 10000) t ORDERBY RAND() LIMIT 10;
Eine Möglichkeit, die ich ziemlich gut finde, wenn es eine automatisch generierte ID gibt, ist die Verwendung des Modulo-Operators '%'. Wenn Sie beispielsweise 10.000 zufällige Datensätze von 70.000 benötigen, können Sie dies vereinfachen, indem Sie sagen, dass Sie 1 von 7 Zeilen benötigen. Dies kann in dieser Abfrage vereinfacht werden:
SELECT*FROMtableWHERE
id %
FLOOR((SELECT count(1)FROMtable)/10000)=0;
Wenn das Ergebnis der Division der Zielzeilen durch die verfügbare Gesamtzahl keine Ganzzahl ist, stehen Ihnen einige zusätzliche Zeilen zur Verfügung, als Sie angefordert haben. Fügen Sie daher eine LIMIT-Klausel hinzu, um die Ergebnismenge wie folgt zu kürzen:
SELECT*FROMtableWHERE
id %
FLOOR((SELECT count(1)FROMtable)/10000)=0
LIMIT 10000;
Dies erfordert einen vollständigen Scan, ist jedoch schneller als ORDER BY RAND und meiner Meinung nach einfacher zu verstehen als andere in diesem Thread erwähnte Optionen. Auch wenn das System, das in die Datenbank schreibt, Sätze von Zeilen in Stapeln erstellt, erhalten Sie möglicherweise kein so zufälliges Ergebnis, wie Sie es erwartet haben.
Nun, da ich denke, wenn Sie jedes Mal, wenn Sie es aufrufen, zufällige Zeilen benötigen, ist dies nutzlos. Ich habe nur über die Notwendigkeit nachgedacht, zufällige Zeilen aus einem Satz zu erhalten, um Nachforschungen anzustellen. Ich denke immer noch, dass Modulo eine gute Sache ist, um im anderen Fall zu helfen. Sie können Modulo als First-Pass-Filter verwenden, um die Kosten einer ORDER BY RAND-Operation zu senken.
Nicolas Cohen
1
Wenn Sie einen zufälligen Datensatz möchten (unabhängig davon, ob zwischen den IDs Lücken bestehen):
Ich habe alle Antworten durchgesehen, und ich glaube, niemand erwähnt diese Möglichkeit überhaupt, und ich bin mir nicht sicher, warum.
Wenn Sie äußerste Einfachheit und Geschwindigkeit zu geringen Kosten wünschen, erscheint es mir sinnvoll, eine Zufallszahl für jede Zeile in der Datenbank zu speichern. Erstellen Sie einfach eine zusätzliche Spalte random_numberund setzen Sie die Standardeinstellung auf RAND(). Erstellen Sie einen Index für diese Spalte.
Wenn Sie dann eine Zeile abrufen möchten, generieren Sie eine Zufallszahl in Ihrem Code (PHP, Perl, was auch immer) und vergleichen Sie diese mit der Spalte.
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
Ich denke, obwohl es für eine einzelne Zeile sehr ordentlich ist, müssten Sie es für zehn Zeilen wie das OP zehn Mal einzeln aufrufen (oder sich eine clevere Optimierung einfallen lassen, die mir sofort entgeht).
Dies ist eigentlich ein sehr schöner und effizienter Ansatz. Der einzige Nachteil ist die Tatsache, dass Sie Platz gegen Geschwindigkeit eingetauscht haben, was meiner Meinung nach ein faires Geschäft ist.
Tochukwu Nkemdilim
Vielen Dank. Ich hatte ein Szenario, in dem die Haupttabelle, aus der ich eine zufällige Zeile haben wollte, 5 Millionen Zeilen und ziemlich viele Verknüpfungen hatte, und nachdem ich die meisten Ansätze in dieser Frage ausprobiert hatte, war dies der Kludge, auf den ich mich festgelegt hatte. Eine zusätzliche Kolumne war für mich ein sehr lohnender Kompromiss.
Codemonkey
0
Das Folgende sollte schnell, unvoreingenommen und unabhängig von der ID-Spalte sein. Es kann jedoch nicht garantiert werden, dass die Anzahl der zurückgegebenen Zeilen mit der Anzahl der angeforderten Zeilen übereinstimmt.
SELECT*FROM t
WHERE RAND()<(SELECT10/ COUNT(*)FROM t)
Erläuterung: Angenommen, Sie möchten 10 von 100 Zeilen, dann hat jede Zeile eine Wahrscheinlichkeit von 1/10, ausgewählt zu werden, was durch erreicht werden könnte WHERE RAND() < 0.1. Dieser Ansatz garantiert nicht 10 Zeilen; Wenn die Abfrage jedoch genügend oft ausgeführt wird, beträgt die durchschnittliche Anzahl der Zeilen pro Ausführung etwa 10, und jede Zeile in der Tabelle wird gleichmäßig ausgewählt.
Sie können auch eine where-Klausel wie diese anwenden
PREPARE stm from'select * from table where available=true limit 10 offset ?';SET@total =(select count(*)fromtablewhere available=true);SET@_offset = FLOOR(RAND()*@total);EXECUTE stm using@_offset;
Die Ausführung der Tabellenabfrage mit 600.000 Zeilen (700 MB) dauerte ~ 0,016 Sekunden. Festplattenlaufwerk
--EDIT--
Der Offset kann einen Wert nahe dem Ende der Tabelle annehmen, was dazu führt, dass die select-Anweisung weniger Zeilen (oder möglicherweise nur 1) zurückgibt row), um dies zu vermeiden, können wir das offseterneut überprüfen , nachdem wir es deklariert haben
Zur Hölle, nein, das ist eine der schlechtesten Möglichkeiten, zufällige Zeilen aus der Tabelle zu erhalten. Das ist vollständiger Tabellenscan + Dateisortierung + tmp-Tabelle = schlechte Leistung.
Matt
1
Neben der Leistung ist es auch alles andere als zufällig. Sie bestellen nach dem Produkt aus der ID und einer Zufallszahl, anstatt nur nach einer Zufallszahl zu bestellen. Dies bedeutet, dass Zeilen mit niedrigeren IDs dazu neigen, früher in Ihrer Ergebnismenge zu erscheinen.
Antworten:
Ein großartiger Beitrag, der mehrere Fälle bearbeitet, von einfach über Lücken bis hin zu ungleichmäßigen Lücken.
http://jan.kneschke.de/projects/mysql/order-by-rand/
Im allgemeinsten Fall gehen Sie folgendermaßen vor:
Dies setzt voraus, dass die Verteilung der IDs gleich ist und dass es Lücken in der ID-Liste geben kann. Weitere Informationen finden Sie im Artikel
quelle
mysqli_fetch_assoc($result)
? Oder sind diese 10 Ergebnisse nicht unbedingt unterscheidbar?Nicht die effiziente Lösung, funktioniert aber
quelle
ORDER BY RAND()
ist relativ langsamSELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10
dauert 0,0010, ohne LIMIT 10 dauerte es 0,0012 (in dieser Tabelle 3500 Wörter).Einfache Abfrage, die eine hervorragende Leistung aufweist und mit Lücken arbeitet :
Diese Abfrage für eine 200K-Tabelle dauert 0,08 Sekunden und die normale Version (SELECT * FROM tbl ORDER BY RAND () LIMIT 10) dauert 0,35 Sekunden auf meinem Computer .
Dies ist schnell, da in der Sortierphase nur die indizierte ID-Spalte verwendet wird. Sie können dieses Verhalten in der Erklärung sehen:
SELECT * FROM tbl ORDER BY RAND () LIMIT 10:
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND () LIMIT 10) als t2 ON t1.id = t2.id.
Gewichtete Version : https://stackoverflow.com/a/41577458/893432
quelle
Ich erhalte schnelle Abfragen (ca. 0,5 Sekunden) mit einer langsamen CPU und wähle 10 zufällige Zeilen in einer nicht zwischengespeicherten 2-GB-Größe der MySQL-Datenbank mit 400 KB aus. Siehe hier meinen Code: Schnelle Auswahl von zufälligen Zeilen in MySQL
quelle
ORDER BY RAND()
FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';
, um es zu sehen.ORDER BY RAND()
besteht darin, dass nur die IDs (nicht die vollständigen Zeilen) sortiert werden, sodass die temporäre Tabelle kleiner ist, aber dennoch alle sortiert werden muss.Es ist eine sehr einfache und einzeilige Abfrage.
quelle
order by rand()
Aus dem Buch:
Wählen Sie eine zufällige Zeile mit einem Versatz
Eine weitere Technik, die Probleme in den vorhergehenden Alternativen vermeidet, besteht darin, die Zeilen im Datensatz zu zählen und eine Zufallszahl zwischen 0 und der Anzahl zurückzugeben. Verwenden Sie diese Nummer dann als Offset, wenn Sie den Datensatz abfragen
Verwenden Sie diese Lösung, wenn Sie keine zusammenhängenden Schlüsselwerte annehmen können und sicherstellen müssen, dass jede Zeile eine gleichmäßige Chance hat, ausgewählt zu werden.
quelle
SELECT count(*)
wird langsam.So wählen Sie zufällige Zeilen aus einer Tabelle aus:
Von hier aus: Wählen Sie zufällige Zeilen in MySQL aus
Eine schnelle Verbesserung gegenüber "Tabellenscan" besteht darin, den Index zum Abrufen zufälliger IDs zu verwenden.
quelle
PRIMARY KEY
).Wenn Ihre Schlüssel keine Lücken aufweisen und alle numerisch sind, können Sie Zufallszahlen berechnen und diese Zeilen auswählen. Dies wird aber wahrscheinlich nicht der Fall sein.
Eine Lösung wäre also die folgende:
Dies stellt im Grunde sicher, dass Sie eine Zufallszahl im Bereich Ihrer Tasten erhalten und dann die nächstbeste auswählen, die größer ist. Sie müssen dies 10 Mal tun.
Dies ist jedoch NICHT wirklich zufällig, da Ihre Schlüssel höchstwahrscheinlich nicht gleichmäßig verteilt werden.
Es ist wirklich ein großes Problem und nicht einfach zu lösen, um alle Anforderungen zu erfüllen. Rand () von MySQL ist das Beste, was Sie bekommen können, wenn Sie wirklich 10 zufällige Zeilen wollen.
Es gibt jedoch eine andere Lösung, die schnell ist, aber auch einen Kompromiss in Bezug auf Zufälligkeit aufweist, aber möglicherweise besser zu Ihnen passt. Lesen Sie hier darüber: Wie kann ich die ORDER BY RAND () - Funktion von MySQL optimieren?
Die Frage ist, wie zufällig Sie es brauchen.
Können Sie uns etwas mehr erklären, damit ich Ihnen eine gute Lösung geben kann?
Zum Beispiel hatte ein Unternehmen, mit dem ich zusammengearbeitet habe, eine Lösung, bei der es extrem schnell um absolute Zufälligkeit ging. Am Ende wurde die Datenbank mit Zufallswerten gefüllt, die absteigend ausgewählt und anschließend wieder auf andere Zufallswerte gesetzt wurden.
Wenn Sie kaum jemals aktualisieren, können Sie auch eine inkrementelle ID eingeben, damit Sie keine Lücken haben und vor der Auswahl nur zufällige Schlüssel berechnen können ... Dies hängt vom Anwendungsfall ab!
quelle
Id
und alle Ihre zufälligen Abfragen geben Ihnen diese zurückId
.FLOOR(RAND()*MAX(id))
ist voreingenommen in Richtung der Rückgabe größerer IDs.Ich brauchte eine Abfrage, um eine große Anzahl zufälliger Zeilen aus einer ziemlich großen Tabelle zurückzugeben. Das habe ich mir ausgedacht. Erhalten Sie zuerst die maximale Datensatz-ID:
Ersetzen Sie diesen Wert dann durch:
Dabei ist max die maximale Datensatz-ID in der Tabelle und n die Anzahl der Zeilen, die Sie in Ihrer Ergebnismenge haben möchten. Die Annahme ist, dass es keine Lücken in den Datensatz-IDs gibt, obwohl ich bezweifle, dass dies das Ergebnis beeinflussen würde, wenn es solche gäbe (habe es aber nicht versucht). Ich habe diese gespeicherte Prozedur auch allgemeiner erstellt. Übergeben Sie den Tabellennamen und die Anzahl der zurückzugebenden Zeilen. Ich verwende MySQL 5.5.38 unter Windows 2008, 32 GB, Dual 3 GHz E5450 und in einer Tabelle mit 17.361.264 Zeilen ist es mit ~ 0,03 Sekunden / ~ 11 Sekunden ziemlich konsistent, um 1.000.000 Zeilen zurückzugeben. (Die Zeiten stammen aus MySQL Workbench 6.1. Sie können in der zweiten select-Anweisung auch CEIL anstelle von FLOOR verwenden, je nach Ihren Vorlieben.)
dann
quelle
Die besten Antworten wurden bereits veröffentlicht (hauptsächlich diejenigen, die auf den Link http://jan.kneschke.de/projects/mysql/order-by-rand/ verweisen ).
Ich möchte eine andere Möglichkeit der Beschleunigung aufzeigen - das Caching . Überlegen Sie, warum Sie zufällige Zeilen benötigen. Wahrscheinlich möchten Sie einen zufälligen Beitrag oder eine zufällige Anzeige auf einer Website anzeigen. Wenn Sie 100 Anforderungen / s erhalten, ist es wirklich erforderlich, dass jeder Besucher zufällige Zeilen erhält? Normalerweise ist es völlig in Ordnung, diese X zufälligen Zeilen 1 Sekunde (oder sogar 10 Sekunden) zwischenzuspeichern. Es spielt keine Rolle, ob 100 eindeutige Besucher in derselben Sekunde dieselben zufälligen Beiträge erhalten, da in der nächsten Sekunde weitere 100 Besucher unterschiedliche Beiträge erhalten.
Wenn Sie dieses Caching verwenden, können Sie auch einige der langsameren Lösungen zum Abrufen der Zufallsdaten verwenden, da diese unabhängig von Ihren Anforderungen nur einmal pro Sekunde von MySQL abgerufen werden.
quelle
Ich habe die Antwort von @Riedsio verbessert. Dies ist die effizienteste Abfrage, die ich für eine große, gleichmäßig verteilte Tabelle mit Lücken finden kann (getestet, um 1000 zufällige Zeilen aus einer Tabelle mit> 2,6B Zeilen zu erhalten).
Lassen Sie mich auspacken, was los ist.
@max := (SELECT MAX(id) FROM table)
MAX(id)
jedes Mal, wenn Sie eine Zeile benötigenSELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
Durch die Vereinigung können Sie alles in eine Abfrage einpassen, sodass Sie nicht mehrere Abfragen ausführen müssen. Sie können damit auch den Aufwand für die Berechnung sparen
MAX(id)
. Abhängig von Ihrer Anwendung kann dies sehr oder sehr wenig bedeuten.Beachten Sie, dass dadurch nur die IDs und in zufälliger Reihenfolge abgerufen werden. Wenn Sie etwas Fortgeschritteneres tun möchten, empfehle ich Ihnen Folgendes:
quelle
LIMIT 1
umLIMIT 30
in Abfrage überallLIMIT 1
zuLIMIT 30
30 Datensätze in einer Reihe von einem zufälligen Punkt in der Tabelle erhalten würde. Sie sollten stattdessen 30 Kopien des(SELECT id FROM ....
Teils in der Mitte haben.Riedsio
antworten. Ich habe mit 500 pro Sekunde Treffer auf die Seite mit PHP 7.0.22 und MariaDB auf Centos 7 versucht. Mit derRiedsio
Antwort habe ich mehr als 500 zusätzliche erfolgreiche Antworten erhalten als Ihre Antwort.Ich habe diese http://jan.kneschke.de/projects/mysql/order-by-rand/ von Riedsio verwendet (ich habe den Fall einer gespeicherten Prozedur verwendet, die einen oder mehrere zufällige Werte zurückgibt):
In dem Artikel löst er das Problem von Lücken in IDs, die nicht so zufällige Ergebnisse verursachen, indem er eine Tabelle verwaltet (unter Verwendung von Triggern usw. ... siehe Artikel); Ich löse das Problem, indem ich der Tabelle eine weitere Spalte hinzufüge, die mit zusammenhängenden Zahlen gefüllt ist, beginnend mit 1 (hinzufüge Bearbeiten: Diese Spalte wird der temporären Tabelle hinzugefügt, die zur Laufzeit von der Unterabfrage erstellt wurde, wirkt sich nicht auf Ihre permanente Tabelle aus):
In dem Artikel kann ich sehen, dass er große Anstrengungen unternommen hat, um den Code zu optimieren. Ich habe keine Ahnung, ob / wie sehr sich meine Änderungen auf die Leistung auswirken, aber es funktioniert sehr gut für mich.
quelle
@no_gaps_id
kein Index verwendet werden kann, so dass , wenn man sich anschaut ,EXPLAIN
für Ihre Anfrage, Sie habenUsing filesort
undUsing where
(ohne Index) für die Unterabfragen, im Gegensatz zu der ursprünglichen Abfrage.Hier ist ein Game Changer, der für viele hilfreich sein kann.
Ich habe eine Tabelle mit 200.000 Zeilen und sequentiellen IDs. Ich musste N zufällige Zeilen auswählen. Daher habe ich mich dafür entschieden, zufällige Werte basierend auf der größten ID in der Tabelle zu generieren. Ich habe dieses Skript erstellt, um herauszufinden, welche Operation die schnellste ist:
Die Ergebnisse sind:
36.8418693542479
ms0.241041183472
ms0.216960906982
msBasierend auf diesen Ergebnissen ist order desc die schnellste Operation, um die maximale ID zu erhalten.
Hier ist meine Antwort auf die Frage:
Zu Ihrer Information: Um 10 zufällige Zeilen aus einer 200k-Tabelle zu erhalten, habe ich 1,78 ms gebraucht (einschließlich aller Operationen auf der PHP-Seite).
quelle
LIMIT
geringfügig erhöhen - Sie können Duplikate erhalten.Dies ist super schnell und 100% zufällig, auch wenn Sie Lücken haben.
x
der verfügbaren ZeilenSELECT COUNT(*) as rows FROM TABLE
a_1,a_2,...,a_10
zwischen 0 undx
SELECT * FROM TABLE LIMIT 1 offset a_i
für i = 1, ..., 10Ich habe diesen Hack in dem Buch SQL Antipatterns von Bill Karwin gefunden .
quelle
SELECT column FROM table ORDER BY RAND() LIMIT 10
in O (nlog (n)) befindet. Ja, dies ist die schnellste Lösung und funktioniert für jede Verteilung von IDs.x
. Ich würde argumentieren, dass dies keine zufällige Generation von 10 Zeilen ist. In meiner Antwort müssen Sie die Abfrage in Schritt drei zehnmal ausführen, dh man erhält nur eine Zeile pro Ausführung und muss sich keine Sorgen machen, wenn der Offset am Ende der Tabelle steht.Wenn Sie nur eine Leseanforderung haben
Kombinieren Sie die Antwort von @redsio mit einer temporären Tabelle (600K sind nicht so viel):
Und dann nimm eine Version von @redsios Antwort:
Wenn der Tisch groß ist, können Sie den ersten Teil sieben:
Wenn Sie viele Leseanfragen haben
Version: Sie könnten die Tabelle behalten
tmp_randorder
persistent halten und als datatable_idlist bezeichnen. Erstellen Sie diese Tabelle in bestimmten Intervallen (Tag, Stunde) neu, da sie auch Löcher bekommt. Wenn Ihr Tisch wirklich groß wird, können Sie auch Löcher nachfüllenWählen Sie l.data_id als Ganzes aus der Liste datatable_id aus. l left join datatable dt on dt.id = l.data_id wobei dt.id null ist.
Version: Geben Sie Ihrem Dataset eine random_sortorder-Spalte entweder direkt in datatable oder in einer persistenten zusätzlichen Tabelle
datatable_sortorder
. Indizieren Sie diese Spalte. Generieren Sie einen Zufallswert in Ihrer Anwendung (ich werde es nennen$rand
).Diese Lösung unterscheidet die 'Kantenzeilen' mit der höchsten und der niedrigsten random_sortorder, also ordnen Sie sie in Intervallen (einmal am Tag) neu an.
quelle
Eine andere einfache Lösung wäre, die Zeilen zu ordnen und eine davon zufällig abzurufen. Mit dieser Lösung müssen Sie keine 'Id'-basierte Spalte in der Tabelle haben.
Sie können den Grenzwert nach Bedarf ändern, um auf so viele Zeilen zuzugreifen, wie Sie möchten. Dies sind jedoch meistens aufeinanderfolgende Werte.
Wenn Sie jedoch keine aufeinanderfolgenden Zufallswerte möchten, können Sie eine größere Stichprobe abrufen und zufällig auswählen. etwas wie ...
quelle
Eine Möglichkeit, die ich ziemlich gut finde, wenn es eine automatisch generierte ID gibt, ist die Verwendung des Modulo-Operators '%'. Wenn Sie beispielsweise 10.000 zufällige Datensätze von 70.000 benötigen, können Sie dies vereinfachen, indem Sie sagen, dass Sie 1 von 7 Zeilen benötigen. Dies kann in dieser Abfrage vereinfacht werden:
Wenn das Ergebnis der Division der Zielzeilen durch die verfügbare Gesamtzahl keine Ganzzahl ist, stehen Ihnen einige zusätzliche Zeilen zur Verfügung, als Sie angefordert haben. Fügen Sie daher eine LIMIT-Klausel hinzu, um die Ergebnismenge wie folgt zu kürzen:
Dies erfordert einen vollständigen Scan, ist jedoch schneller als ORDER BY RAND und meiner Meinung nach einfacher zu verstehen als andere in diesem Thread erwähnte Optionen. Auch wenn das System, das in die Datenbank schreibt, Sätze von Zeilen in Stapeln erstellt, erhalten Sie möglicherweise kein so zufälliges Ergebnis, wie Sie es erwartet haben.
quelle
Wenn Sie einen zufälligen Datensatz möchten (unabhängig davon, ob zwischen den IDs Lücken bestehen):
Quelle: https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/#comment-1266
quelle
Ich habe alle Antworten durchgesehen, und ich glaube, niemand erwähnt diese Möglichkeit überhaupt, und ich bin mir nicht sicher, warum.
Wenn Sie äußerste Einfachheit und Geschwindigkeit zu geringen Kosten wünschen, erscheint es mir sinnvoll, eine Zufallszahl für jede Zeile in der Datenbank zu speichern. Erstellen Sie einfach eine zusätzliche Spalte
random_number
und setzen Sie die Standardeinstellung aufRAND()
. Erstellen Sie einen Index für diese Spalte.Wenn Sie dann eine Zeile abrufen möchten, generieren Sie eine Zufallszahl in Ihrem Code (PHP, Perl, was auch immer) und vergleichen Sie diese mit der Spalte.
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
Ich denke, obwohl es für eine einzelne Zeile sehr ordentlich ist, müssten Sie es für zehn Zeilen wie das OP zehn Mal einzeln aufrufen (oder sich eine clevere Optimierung einfallen lassen, die mir sofort entgeht).
quelle
Das Folgende sollte schnell, unvoreingenommen und unabhängig von der ID-Spalte sein. Es kann jedoch nicht garantiert werden, dass die Anzahl der zurückgegebenen Zeilen mit der Anzahl der angeforderten Zeilen übereinstimmt.
Erläuterung: Angenommen, Sie möchten 10 von 100 Zeilen, dann hat jede Zeile eine Wahrscheinlichkeit von 1/10, ausgewählt zu werden, was durch erreicht werden könnte
WHERE RAND() < 0.1
. Dieser Ansatz garantiert nicht 10 Zeilen; Wenn die Abfrage jedoch genügend oft ausgeführt wird, beträgt die durchschnittliche Anzahl der Zeilen pro Ausführung etwa 10, und jede Zeile in der Tabelle wird gleichmäßig ausgewählt.quelle
Sie können leicht einen zufälligen Versatz mit einem Limit verwenden
Sie können auch eine where-Klausel wie diese anwenden
Die Ausführung der Tabellenabfrage mit 600.000 Zeilen (700 MB) dauerte ~ 0,016 Sekunden. Festplattenlaufwerk
--EDIT--
Der Offset kann einen Wert nahe dem Ende der Tabelle annehmen, was dazu führt, dass die select-Anweisung weniger Zeilen (oder möglicherweise nur 1) zurückgibt row), um dies zu vermeiden, können wir das
offset
erneut überprüfen , nachdem wir es deklariert habenquelle
Ich benutze diese Abfrage:
Abfragezeit: 0,016 s
quelle
So mache ich es:
Ich mag es, weil keine anderen Tabellen erforderlich sind, es einfach zu schreiben ist und sehr schnell ausgeführt werden kann.
quelle
Verwenden Sie die folgende einfache Abfrage, um zufällige Daten aus einer Tabelle abzurufen.
quelle
Ich denke, das ist der bestmögliche Weg.
quelle