schnelle Auswahl einer Zufalls Zeile aus einer großen Tabelle in mysql
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.
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;