Ich habe eine Tabelle in Postgres, die einige Millionen Zeilen enthält. Ich habe im Internet nachgesehen und Folgendes gefunden
SELECT myid FROM mytable ORDER BY RANDOM() LIMIT 1;
Es funktioniert, aber es ist sehr langsam ... gibt es eine andere Möglichkeit, diese Abfrage durchzuführen, oder eine direkte Möglichkeit, eine zufällige Zeile auszuwählen, ohne die gesamte Tabelle zu lesen? Übrigens ist 'myid' eine ganze Zahl, aber es kann ein leeres Feld sein.
Antworten:
Sie könnten mit experimentieren wollen
OFFSET
, wie inSELECT myid FROM mytable OFFSET floor(random()*N) LIMIT 1;
Das
N
ist die Anzahl der Zeilen inmytable
. Möglicherweise müssen Sie zuerst aSELECT COUNT(*)
ausführen, um den Wert von herauszufindenN
.Update (von Antony Hatchkins)
Sie müssen
floor
hier verwenden:Betrachten Sie eine Tabelle mit 2 Zeilen.
random()*N
generiert0 <= x < 2
und gibt beispielsweiseSELECT myid FROM mytable OFFSET 1.7 LIMIT 1;
0 Zeilen zurück, da implizit auf das nächste int gerundet wird.quelle
SELECT COUNT(*)
? zu verwenden ? Ich meine, nicht alle Werte in der Tabelle zu verwenden, sondern nur einen Teil davon?EXPLAIN SELECT ...
mit unterschiedlichen Werten von N verwenden, ergeben sich die gleichen Kosten für die Abfrage. Dann ist es wahrscheinlich besser, den Maximalwert von NPostgreSQL 9.5 führte einen neuen Ansatz für eine viel schnellere Stichprobenauswahl ein: TABLESAMPLE
Die Syntax lautet
Dies ist nicht die optimale Lösung, wenn nur eine Zeile ausgewählt werden soll, da Sie den COUNT der Tabelle kennen müssen, um den genauen Prozentsatz zu berechnen.
Um eine langsame Zählung zu vermeiden und schnelles TABLESAMPLE für Tabellen von 1 Zeile bis Milliarden von Zeilen zu verwenden, haben Sie folgende Möglichkeiten:
Dies sieht vielleicht nicht so elegant aus, ist aber wahrscheinlich schneller als jede andere Antwort.
Informationen zur Entscheidung, ob Sie BERNULLI oder SYSTEM verwenden möchten, finden Sie unter http://blog.2ndquadrant.com/tablesample-in-postgresql-9-5-2/.
quelle
SELECT * FROM my_table TABLESAMPLE SYSTEM(SELECT 1/COUNT(*) FROM my_table) LIMIT 1;
?SELECT reltuples FROM pg_class WHERE relname = 'my_table'
.Ich habe dies mit einer Unterabfrage versucht und es hat gut funktioniert. Offset funktioniert zumindest in Postgresql v8.4.4 einwandfrei.
quelle
Sie müssen verwenden
floor
:quelle
random()*N
generiert 0 <= x <2 und gibt beispielsweiseSELECT myid FROM mytable OFFSET 1.7 LIMIT 1;
0 Zeilen zurück, weil implizit auf das nächste int gerundet wird.order by random()
, ungefähr so, wie die3*O(N) < O(NlogN)
realen Zahlen aufgrund von Indizes leicht abweichen.WHERE myid NOT IN (1st-myid)
undWHERE myid NOT IN (1st-myid, 2nd-myid)
nicht funktionieren würden, da die Entscheidung vom OFFSET getroffen wird. Hmmm ... Ich denke, ich könnte N im zweiten und dritten SELECT um 1 und 2 reduzieren.floor()
? Welchen Vorteil bietet es?Überprüfen Sie diesen Link für einige verschiedene Optionen. http://www.depesz.com/index.php/2007/09/16/my- Thoughts-on-getting-random-row/
Aktualisieren: (A. Hatchkins)
Die Zusammenfassung des (sehr) langen Artikels lautet wie folgt.
Der Autor listet vier Ansätze auf:
1)
ORDER BY random() LIMIT 1;
- langsam2)
ORDER BY id where id>=random()*N LIMIT 1
- ungleichmäßig, wenn es Lücken gibt3) zufällige Spalte - muss von Zeit zu Zeit aktualisiert werden
4) Benutzerdefinierte Zufallsaggregat - Listmethode, könnte langsam sein: random () muss N-mal generiert werden
und schlägt vor, Methode 2 durch Verwendung zu verbessern
5)
ORDER BY id where id=random()*N LIMIT 1
mit nachfolgenden Anfragen, wenn das Ergebnis leer ist.quelle
Ich habe eine sehr schnelle Lösung ohne gefunden
TABLESAMPLE
. Viel schneller alsOFFSET random()*N LIMIT 1
. Es erfordert nicht einmal die Anzahl der Tabellen.Die Idee ist beispielsweise, einen Ausdrucksindex mit zufälligen, aber vorhersehbaren Daten zu erstellen
md5(primary key)
.Hier ist ein Test mit Beispieldaten für 1 Million Zeilen:
Ergebnis:
Diese Abfrage kann manchmal (mit einer Wahrscheinlichkeit von ungefähr 1 / Anzahl_der_Zeilen) 0 Zeilen zurückgeben, daher muss sie überprüft und erneut ausgeführt werden. Auch die Wahrscheinlichkeiten sind nicht genau gleich - einige Zeilen sind wahrscheinlicher als andere.
Zum Vergleich:
Die Ergebnisse variieren stark, können aber ziemlich schlecht sein:
quelle
Der einfachste und schnellste Weg, um zufällige Zeilen abzurufen, ist die Verwendung der
tsm_system_rows
Erweiterung:Dann können Sie die genaue Anzahl der gewünschten Zeilen auswählen:
Dies ist mit PostgreSQL 9.5 und höher verfügbar.
Siehe: https://www.postgresql.org/docs/current/static/tsm-system-rows.html
quelle
ORDER BY random() LIMIT 1;
sollte dieser schnell genug sein.