Wie fordere ich eine zufällige Zeile in SQL an?

510

Wie kann ich in reinem SQL eine zufällige Zeile anfordern (oder so nah wie möglich an einer wirklich zufälligen Zeile)?

sverrejoh
quelle
Ich habe dies immer in PHP gemacht, nachdem Abfrageergebnisse von SQL ... dies ist wahrscheinlich viel schneller für die Verarbeitung gemäß dem Anhang der Lösung zu Limit 1
CheeseConQueso
2
Es scheint, dass es keine "reine SQL" -Lösung gibt, die auf jeder Datenbank ausgeführt wird ... es gibt für jede eine Lösung.
Manu
Performance-Version: stackoverflow.com/questions/4329396/…
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Antworten:

735

Siehe diesen Beitrag: SQL zum Auswählen einer zufälligen Zeile aus einer Datenbanktabelle . Hierzu werden Methoden in MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 und Oracle beschrieben (Folgendes wird von diesem Link kopiert):

Wählen Sie mit MySQL eine zufällige Zeile aus:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Wählen Sie mit PostgreSQL eine zufällige Zeile aus:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Wählen Sie mit Microsoft SQL Server eine zufällige Zeile aus:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Wählen Sie mit IBM DB2 eine zufällige Zeile aus

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

Wählen Sie mit Oracle einen zufälligen Datensatz aus:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1
Yaakov Ellis
quelle
30
-1 für das order by rand()Verlassen auf oder Äquivalente in allen dbs: |. auch hier erwähnt .
AD7six
20
Vor zehn Jahren sagte ein Typ, dass die Verwendung ORDER BY RAND()falsch ist ...
Trejder
ORDER BY NEWID () scheint auf SQL Server deutlich langsamer zu sein. Meine Abfrage sieht folgendermaßen aus: Wählen Sie die Top 1000 C.CustomerId, CL.LoginName aus dem inneren Join von Kunde C LinkedAccount LA auf C.CustomerId = LA.CustomerId innerer Join CustomerLogin CL auf der Gruppe C.CustomerId = CL.CustomerId von C.CustomerId, CL. LoginName mit count (*)> 1 order by NEWID () Durch Entfernen der Zeile "order by NEWID ()" werden die Ergebnisse viel schneller zurückgegeben.
Ben Power
3
Verwenden Sie für SQLite die Funktion RANDOM ().
Slam
10
Diese Lösungen skalieren nicht. Sie sind O(n)mit nder Anzahl der Datensätze in der Tabelle. Stellen Sie sich vor, Sie haben 1 Million Datensätze. Möchten Sie wirklich 1 Million Zufallszahlen oder eindeutige IDs generieren? Ich würde das lieber verwenden COUNT()und in einen neuen LIMITAusdruck mit einer einzelnen Zufallszahl einbeziehen .
Christian Hujer
174

Lösungen wie Jeremies:

SELECT * FROM table ORDER BY RAND() LIMIT 1

funktionieren, aber sie benötigen einen sequentiellen Scan der gesamten Tabelle (da der jeder Zeile zugeordnete Zufallswert berechnet werden muss, damit der kleinste ermittelt werden kann), was selbst für mittelgroße Tabellen recht langsam sein kann. Meine Empfehlung wäre, eine Art indizierte numerische Spalte zu verwenden (viele Tabellen haben diese als Primärschlüssel) und dann etwas zu schreiben wie:

SELECT * FROM table WHERE num_value >= RAND() * 
    ( SELECT MAX (num_value ) FROM table ) 
ORDER BY num_value LIMIT 1

Dies funktioniert in logarithmischer Zeit, unabhängig von der Tabellengröße, wenn num_valueindiziert. Eine Einschränkung: Dies setzt voraus, dass die num_valueVerteilung im Bereich gleichmäßig ist 0..MAX(num_value). Wenn Ihr Datensatz stark von dieser Annahme abweicht, erhalten Sie verzerrte Ergebnisse (einige Zeilen werden häufiger angezeigt als andere).

Grauer Panther
quelle
8
Der zweite Vorschlag ist nicht zufällig. Sie können nicht vorhersagen, welche Reihe ausgewählt wird, aber wenn Sie wetten müssten, würden Sie auf die zweite Reihe wetten. Und Sie würden nie auf die letzte Reihe wetten, es ist weniger wahrscheinlich, dass Sie ausgewählt werden, unabhängig von der Verteilung Ihres num_value und der Größe Ihres Tisches.
Etienne Racine
1
Ich weiß, dass RAND () -Funktionen normalerweise nicht von sehr hoher Qualität sind, aber ansonsten können Sie bitte erläutern, warum die Auswahl nicht zufällig ist.
Grey Panther
13
Der erste ist FALSCH in SQL Server. Die Funktion RAND () wird nur einmal pro Abfrage und nicht einmal pro Zeile aufgerufen. Es wird also immer die erste Zeile ausgewählt (probieren Sie es aus).
Jeff Walker Code Ranger
3
Beim zweiten wird ebenfalls davon ausgegangen, dass alle Zeilen berücksichtigt werden: Möglicherweise wird eine gelöschte Zeile ausgewählt.
Sam Rueby
3
@ Sam.Rueby Tatsächlich stellt num_value> = RAND () ... limit 1 sicher, dass leere Zeilen übersprungen werden, bis eine vorhandene Zeile gefunden wird.
Ghord
62

Ich weiß nicht, wie effizient das ist, aber ich habe es schon einmal benutzt:

SELECT TOP 1 * FROM MyTable ORDER BY newid()

Da GUIDs ziemlich zufällig sind, bedeutet die Reihenfolge, dass Sie eine zufällige Zeile erhalten.

Matt Hamilton
quelle
1
Ich verwende MS SQL Server, SELECT TOP 1 * FROM some_table_name ORDER BY NEWID () hat bei mir großartig funktioniert, danke für die Ratschläge, Leute!
Das ist genau das gleiche wieORDER BY RAND() LIMIT 1
Ken Bloom
6
Dies ist auch sehr datenbankspezifisch, da es TOP 1und verwendet newid().
Grau
12
Das ist eine schlechte Idee. Diese Methode verwendet keinen Index, es sei denn, jede Spalte wird einzeln indiziert. Eine Tabelle mit 100 Millionen Datensätzen kann sehr lange dauern, bis ein Datensatz erstellt wird.
Schalten Sie den
1
@Switch und welche Lösung würden Sie vorschlagen?
Akmal Salikhov
31
ORDER BY NEWID()

nimmt 7.4 milliseconds

WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table)

nimmt 0.0065 milliseconds!

Ich werde definitiv mit letzterer Methode gehen.

Neel
quelle
2
Die zweite Option wählt nicht die letzte Zeile aus. Ich weiß nicht warum - ich möchte nur darauf hinweisen.
Voldemort
7
@Voldemort: Gibt rand()eine Gleitkommazahl zurück, nwobei 0 < n < 1. Angenommen, es num_valuehandelt sich um eine Ganzzahl, wird der Rückgabewert von rand() * max(num_value)auch zu einer Ganzzahl gezwungen, wodurch alles nach dem Dezimalpunkt abgeschnitten wird. Daher rand() * max(num_value)wird immer kleiner als sein max(num_value), weshalb die letzte Zeile niemals ausgewählt wird.
Ian Kemp
Ich werde nicht effizient sein, wenn meine Daten häufig gelöscht werden. Wenn ich eine Lücke finde, muss ich die gesamte Abfrage erneut ausführen.
Loic Coenen
1
@ IanKemp Dumme Frage, warum also nicht einfach SELECT MAX (num_value) + 1 verwenden? Da rand (oder in den meisten Fällen RANDOM) [0,1] zurückgibt, erhalten Sie den gesamten Wertebereich. Ja, Sie haben Recht, Sie müssen eine Abfrage korrigieren.
TekHedd
13

Sie haben nicht angegeben, welchen Server Sie verwenden. In älteren Versionen von SQL Server können Sie Folgendes verwenden:

select top 1 * from mytable order by newid()

In SQL Server 2005 und höher können Sie TABLESAMPLEeine zufällige Stichprobe abrufen, die wiederholbar ist:

SELECT FirstName, LastName
FROM Contact 
TABLESAMPLE (1 ROWS) ;
Jon Galloway
quelle
9
MSDN sagt, dass newid () gegenüber Tabellenbeispielen für wirklich zufällige Ergebnisse bevorzugt wird: msdn.microsoft.com/en-us/library/ms189108.aspx
Andrew Hedges
7
@ Andrew Hedges: Bestellung von NEWID () ist zu teuer
Andrei Rînea
10

Für SQL Server

newid () / order by funktioniert, ist jedoch für große Ergebnismengen sehr teuer, da für jede Zeile eine ID generiert und anschließend sortiert werden muss.

TABLESAMPLE () ist vom Standpunkt der Leistung aus gut, aber Sie erhalten eine Zusammenfassung der Ergebnisse (alle Zeilen auf einer Seite werden zurückgegeben).

Für eine bessere echte Zufallsstichprobe ist es am besten, Zeilen zufällig herauszufiltern. Ich habe das folgende Codebeispiel im SQL Server Books Online-Artikel Einschränken von Ergebnismengen mithilfe von TABLESAMPLE gefunden :

Wenn Sie wirklich eine zufällige Stichprobe einzelner Zeilen wünschen, ändern Sie Ihre Abfrage so, dass Zeilen zufällig herausgefiltert werden, anstatt TABLESAMPLE zu verwenden. In der folgenden Abfrage wird beispielsweise die NEWID-Funktion verwendet, um ungefähr ein Prozent der Zeilen der Sales.SalesOrderDetail-Tabelle zurückzugeben:

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
              / CAST (0x7fffffff AS int)

Die SalesOrderID-Spalte ist im CHECKSUM-Ausdruck enthalten, sodass NEWID () einmal pro Zeile ausgewertet wird, um eine Stichprobenauswahl pro Zeile zu erzielen. Der Ausdruck CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) ergibt einen zufälligen Float-Wert zwischen 0 und 1.

Wenn ich gegen eine Tabelle mit 1.000.000 Zeilen laufe, sind hier meine Ergebnisse:

SET STATISTICS TIME ON
SET STATISTICS IO ON

/* newid()
   rows returned: 10000
   logical reads: 3359
   CPU time: 3312 ms
   elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()

/* TABLESAMPLE
   rows returned: 9269 (varies)
   logical reads: 32
   CPU time: 0 ms
   elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)

/* Filter
   rows returned: 9994 (varies)
   logical reads: 3359
   CPU time: 641 ms
   elapsed time: 627 ms
*/    
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) 
              / CAST (0x7fffffff AS int)

SET STATISTICS IO OFF
SET STATISTICS TIME OFF

Wenn Sie mit TABLESAMPLE durchkommen, erhalten Sie die beste Leistung. Verwenden Sie andernfalls die Methode newid () / filter. newid () / order by sollte der letzte Ausweg sein, wenn Sie eine große Ergebnismenge haben.

Rob Boek
quelle
4

Verwenden Sie nach Möglichkeit gespeicherte Anweisungen, um die Ineffizienz beider Indizes für RND () zu vermeiden und ein Datensatznummernfeld zu erstellen.

PREPARE RandomRecord FROM "SELECT * FROM table LIMIT ?, 1";
SET @ n = FLOOR (RAND () * (SELECT COUNT (*) FROM Tabelle));
EXECUTE RandomRecord USING @n;
ldrut
quelle
Diese Lösung sorgt auch dafür, dass zufällige Zeilen zurückgegeben werden, wenn der in der obigen where-Klausel verwendete indizierte numerische Wert nicht gleichmäßig verteilt ist. Selbst wenn es fast genauso lange (konstant) dauert wie bei Verwendung von id_value> = RAND () * MAX (id_value), ist es besser.
Guido
Soweit ich das beurteilen kann, läuft dies nicht in konstanter Zeit, sondern in linearer Zeit. Im schlimmsten Fall entspricht @n der Anzahl der Zeilen in der Tabelle, und "SELECT * FROM table LIMIT ?, 1" wertet @n - 1 Zeilen aus, bis die letzte erreicht ist.
Andres Riofrio
3

Der beste Weg ist, einen zufälligen Wert nur zu diesem Zweck in eine neue Spalte einzufügen und so etwas zu verwenden (Pseude-Code + SQL):

randomNo = random()
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo")

Dies ist die Lösung, die vom MediaWiki-Code verwendet wird. Natürlich gibt es eine gewisse Tendenz gegenüber kleineren Werten, aber sie stellten fest, dass es ausreichend war, den Zufallswert auf Null zu setzen, wenn keine Zeilen abgerufen wurden.

Für die Lösung newid () ist möglicherweise ein vollständiger Tabellenscan erforderlich, damit jeder Zeile eine neue Guid zugewiesen werden kann, die viel weniger leistungsfähig ist.

Die Lösung von rand () funktioniert möglicherweise überhaupt nicht (dh mit MSSQL), da die Funktion nur einmal ausgewertet wird und jeder Zeile dieselbe "Zufallszahl" zugewiesen wird.

Ishmaeel
quelle
1
Wenn Sie 0 Ergebnisse erhalten, erhalten Sie eine nachweislich zufällige Stichprobe (nicht nur "gut genug"). Diese Lösung lässt sich fast auf mehrzeilige Abfragen skalieren (denken Sie an "Party Shuffle"). Das Problem ist, dass die Ergebnisse in der Regel wiederholt in denselben Gruppen ausgewählt werden. Um dies zu umgehen, müssten Sie die soeben verwendeten Zufallszahlen neu verteilen. Sie könnten schummeln, indem Sie randomNo verfolgen und es aus den Ergebnissen auf max (Zufälligkeit) setzen, aber dann p (Zeile i bei Abfrage 1 UND Zeile i bei Abfrage 2) == 0, was nicht fair ist. Lassen Sie mich ein bisschen rechnen, und ich werde mich mit einem wirklich fairen Schema bei Ihnen melden.
Alsuren
3

Wenn wir für SQL Server 2005 und 2008 eine zufällige Stichprobe einzelner Zeilen (aus Books Online ) wünschen :

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
Santiago Cepas
quelle
3

Wenn Sie RAND () verwenden, da dies nicht empfohlen wird , erhalten Sie möglicherweise einfach die maximale ID (= Max):

SELECT MAX(ID) FROM TABLE;

Holen Sie sich einen Zufall zwischen 1..Max (= My_Generated_Random)

My_Generated_Random = rand_in_your_programming_lang_function(1..Max);

und führen Sie dann diese SQL aus:

SELECT ID FROM TABLE WHERE ID >= My_Generated_Random ORDER BY ID LIMIT 1

Beachten Sie, dass nach Zeilen gesucht wird, deren IDs gleich oder höher als der ausgewählte Wert sind. Es ist auch möglich, nach der Zeile in der Tabelle zu suchen und eine gleiche oder niedrigere ID als My_Generated_Random zu erhalten. Ändern Sie dann die Abfrage wie folgt:

SELECT ID FROM TABLE WHERE ID <= My_Generated_Random ORDER BY ID DESC LIMIT 1
Forsberg
quelle
Was würde passieren, wenn die generierte Zufalls-ID nicht mehr in der Tabelle vorhanden ist? Gelöschte oder passive Zeilen, die Sie dem Benutzer nicht anzeigen möchten, verursachen Probleme.
Ebleme
Nichts. Sie erhalten die NÄCHSTE, nicht genaue ID-Nummer. Wenn Sie der Meinung sind, dass id = 1 entfernt werden soll, tauschen Sie 1 mit Minimum aus.
Forsberg
2

Wie in @ BillKarwins Kommentar zu @ cnus Antwort ausgeführt ...

Beim Kombinieren mit einem LIMIT habe ich festgestellt, dass es (zumindest mit PostgreSQL 9.1) viel besser funktioniert, sich einer zufälligen Reihenfolge anzuschließen, als die tatsächlichen Zeilen direkt zu ordnen: z

SELECT * FROM tbl_post AS t
JOIN ...
JOIN ( SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand
       FROM tbl_post
       WHERE create_time >= 1349928000
     ) r ON r.id = t.id
WHERE create_time >= 1349928000 AND ...
ORDER BY r.rand
LIMIT 100

Stellen Sie einfach sicher, dass das 'r' für jeden möglichen Schlüsselwert in der komplexen Abfrage, die damit verbunden ist, einen 'rand'-Wert generiert, aber beschränken Sie die Anzahl der Zeilen von' r 'nach Möglichkeit.

Das CAST als Ganzzahl ist besonders hilfreich für PostgreSQL 9.2, das eine spezifische Sortieroptimierung für Floating-Typen mit Ganzzahl und einfacher Genauigkeit bietet.

Karmakaze
quelle
1

Die meisten Lösungen hier zielen darauf ab, das Sortieren zu vermeiden, müssen jedoch noch einen sequentiellen Scan über eine Tabelle durchführen.

Es gibt auch eine Möglichkeit, den sequentiellen Scan zu vermeiden, indem Sie zum Index-Scan wechseln. Wenn Sie den Indexwert Ihrer zufälligen Zeile kennen, können Sie das Ergebnis fast augenblicklich erhalten. Das Problem ist - wie man einen Indexwert errät.

Die folgende Lösung funktioniert unter PostgreSQL 8.4:

explain analyze select * from cms_refs where rec_id in 
  (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
   from generate_series(1,10))
  limit 1;

In der obigen Lösung erraten Sie 10 verschiedene zufällige Indexwerte aus dem Bereich 0 .. [letzter Wert von id].

Die Zahl 10 ist willkürlich - Sie können 100 oder 1000 verwenden, da dies (erstaunlicherweise) keinen großen Einfluss auf die Reaktionszeit hat.

Es gibt auch ein Problem: Wenn Sie spärliche IDs haben, werden Sie diese möglicherweise übersehen . Die Lösung besteht darin , einen Sicherungsplan zu haben :) In diesem Fall eine reine alte Bestellung per zufälliger () Abfrage. Wenn die kombinierte ID so aussieht:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
     from generate_series(1,10))
    union all (select * from cms_refs order by random() limit 1)
    limit 1;

Nicht die Union ALL- Klausel. In diesem Fall wird der zweite Teil NIEMALS ausgeführt, wenn der erste Teil Daten zurückgibt!

Hegemon
quelle
1

Spät, aber über Google hierher gekommen, werde ich der Nachwelt halber eine alternative Lösung hinzufügen.

Ein anderer Ansatz besteht darin, TOP zweimal mit abwechselnden Bestellungen zu verwenden. Ich weiß nicht, ob es sich um "reines SQL" handelt, da es eine Variable im TOP verwendet, aber es funktioniert in SQL Server 2008. Hier ist ein Beispiel, das ich für eine Tabelle mit Wörterbuchwörtern verwende, wenn ich ein zufälliges Wort möchte.

SELECT TOP 1
  word
FROM (
  SELECT TOP(@idx)
    word 
  FROM
    dbo.DictionaryAbridged WITH(NOLOCK)
  ORDER BY
    word DESC
) AS D
ORDER BY
  word ASC

Natürlich ist @idx eine zufällig generierte Ganzzahl, die in der Zieltabelle einschließlich von 1 bis COUNT (*) reicht. Wenn Ihre Spalte indiziert ist, profitieren Sie auch davon. Ein weiterer Vorteil ist, dass Sie es in einer Funktion verwenden können, da NEWID () nicht zulässig ist.

Schließlich wird die obige Abfrage in etwa 1/10 der Ausführungszeit einer NEWID () - Abfrage in derselben Tabelle ausgeführt. YYMV.

alphadogg
quelle
1

Sie können auch versuchen, die new id()Funktion zu verwenden.

Schreiben Sie einfach Ihre Anfrage und verwenden Sie die Reihenfolge nach new id()Funktion. Es ist ziemlich zufällig.

Jai - gotaninterviewcall
quelle
1

Damit MySQL zufällige Aufzeichnungen erhält

 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

Weitere Details http://jan.kneschke.de/projects/mysql/order-by-rand/

Sophy
quelle
Nachdem ich viele der Antworten getestet habe, glaube ich, dass dies die beste ist. Es scheint schnell zu sein und wählt jedes Mal eine gute Zufallszahl. Es scheint dem zweiten Vorschlag von @GreyPanther oben ähnlich zu sein, aber diese Antwort wählt mehr Zufallszahlen aus.
Jeff Baker
1

Ich habe diese Variation in den Antworten noch nicht ganz gesehen. Ich hatte eine zusätzliche Einschränkung, bei der ich bei einem anfänglichen Startwert jedes Mal denselben Satz von Zeilen auswählen musste.

Für MS SQL:

Minimales Beispiel:

select top 10 percent *
from table_name
order by rand(checksum(*))

Normalisierte Ausführungszeit: 1,00

NewId () Beispiel:

select top 10 percent *
from table_name
order by newid()

Normalisierte Ausführungszeit: 1.02

NewId()ist unwesentlich langsamer als rand(checksum(*)), daher möchten Sie es möglicherweise nicht für große Datensatzgruppen verwenden.

Auswahl mit Initial Seed:

declare @seed int
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */

select top 10 percent *
from table_name
order by rand(checksum(*) % seed) /* any other math function here */

Wenn Sie denselben Satz für einen Startwert auswählen müssen, scheint dies zu funktionieren.

Klyd
quelle
1

In MSSQL (getestet am 11.0.5569) mit

SELECT TOP 100 * FROM employee ORDER BY CRYPT_GEN_RANDOM(10)

ist deutlich schneller als

SELECT TOP 100 * FROM employee ORDER BY NEWID()
David Knight
quelle
1

In SQL Server können Sie TABLESAMPLE mit NEWID () kombinieren, um eine ziemlich gute Zufälligkeit zu erzielen und trotzdem Geschwindigkeit zu haben. Dies ist besonders nützlich, wenn Sie wirklich nur 1 oder eine kleine Anzahl von Zeilen möchten.

SELECT TOP 1 * FROM [table] 
TABLESAMPLE (500 ROWS) 
ORDER BY NEWID()
Chris Arbogast
quelle
1

Mit SQL Server 2012+ können Sie die OFFSET FETCH-Abfrage verwenden , um dies für eine einzelne zufällige Zeile zu tun

select  * from MyTable ORDER BY id OFFSET n ROW FETCH NEXT 1 ROWS ONLY

Dabei ist id eine Identitätsspalte und n die gewünschte Zeile - berechnet als Zufallszahl zwischen 0 und count () - 1 der Tabelle (Offset 0 ist schließlich die erste Zeile).

Dies funktioniert mit Löchern in den Tabellendaten, solange Sie einen Index für die ORDER BY-Klausel haben. Es ist auch sehr gut für die Zufälligkeit - wenn Sie das selbst herausarbeiten, um es weiterzugeben, aber die Probleme bei anderen Methoden sind nicht vorhanden. Außerdem ist die Leistung ziemlich gut, bei einem kleineren Datensatz hält sie gut, obwohl ich keine ernsthaften Leistungstests für mehrere Millionen Zeilen ausprobiert habe.

gbjbaanb
quelle
0
 SELECT * FROM table ORDER BY RAND() LIMIT 1
Jeremy Ruten
quelle
Vor zehn Jahren (2005) sagte ein Typ , dass die Verwendung ORDER BY RAND()falsch ist ...
Trejder
0

Ich muss CD-MaN zustimmen: Die Verwendung von "ORDER BY RAND ()" funktioniert gut für kleine Tabellen oder wenn Sie SELECT nur einige Male ausführen.

Ich verwende auch die Technik "num_value> = RAND () * ...", und wenn ich wirklich zufällige Ergebnisse erzielen möchte, habe ich eine spezielle "zufällige" Spalte in der Tabelle, die ich etwa einmal am Tag aktualisiere. Dieser einzelne UPDATE-Lauf dauert einige Zeit (insbesondere, weil Sie einen Index für diese Spalte benötigen), ist jedoch viel schneller als das Erstellen von Zufallszahlen für jede Zeile bei jedem Ausführen der Auswahl.

BlaM
quelle
0

Seien Sie vorsichtig, da TableSample keine zufällige Stichprobe von Zeilen zurückgibt. Es leitet Ihre Abfrage an, eine zufällige Stichprobe der 8-KB-Seiten zu betrachten, aus denen Ihre Zeile besteht. Anschließend wird Ihre Abfrage anhand der auf diesen Seiten enthaltenen Daten ausgeführt. Aufgrund der Gruppierung von Daten auf diesen Seiten (Einfügereihenfolge usw.) kann dies zu Daten führen, die eigentlich keine Zufallsstichprobe sind.

Siehe: http://www.mssqltips.com/tip.asp?tip=1308

Diese MSDN-Seite für TableSample enthält ein Beispiel für die Generierung einer tatsächlich zufälligen Stichprobe von Daten.

http://msdn.microsoft.com/en-us/library/ms189108.aspx

Sean Turner
quelle
0

Es scheint, dass viele der aufgelisteten Ideen immer noch die Reihenfolge verwenden

Wenn Sie jedoch eine temporäre Tabelle verwenden, können Sie einen zufälligen Index zuweisen (wie viele der Lösungen vorgeschlagen haben) und dann den ersten Index abrufen, der größer als eine beliebige Zahl zwischen 0 und 1 ist.

Zum Beispiel (für DB2):

WITH TEMP AS (
SELECT COMLUMN, RAND() AS IDX FROM TABLE)
SELECT COLUMN FROM TABLE WHERE IDX > .5
FETCH FIRST 1 ROW ONLY
DAVID
quelle
2
Nachdem ich über diese Lösung nachgedacht habe, habe ich einen grundlegenden Fehler in meiner Logik gefunden. Dies würde konsistent dieselben kleinen Einstellungswerte am Anfang der Tabelle zurückgeben, da ich davon ausgehe, dass bei einer gleichmäßigen Verteilung zwischen 0 und 1 eine 50% ige Wahrscheinlichkeit besteht, dass die erste Zeile diese Kriterien erfüllt.
David
0

Es gibt eine bessere Lösung für Oracle, anstatt dbms_random.value zu verwenden, während ein vollständiger Scan erforderlich ist, um Zeilen nach dbms_random.value zu ordnen, und es ist für große Tabellen ziemlich langsam.

Verwenden Sie stattdessen Folgendes:

SELECT *
FROM employee sample(1)
WHERE rownum=1
sev3ryn
quelle
0

Für Firebird:

Select FIRST 1 column from table ORDER BY RAND()
Luigi04
quelle
0

Erweitern Sie für SQL Server 2005 und höher die Antwort von @ GreyPanther für Fälle, in denen num_valuekeine kontinuierlichen Werte vorhanden sind. Dies funktioniert auch in Fällen, in denen wir Datensätze nicht gleichmäßig verteilt haben und in denen num_valuees sich nicht um eine Zahl, sondern um eine eindeutige Kennung handelt.

WITH CTE_Table (SelRow, num_value) 
AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY ID) AS SelRow, num_value FROM table
) 

SELECT * FROM table Where num_value = ( 
    SELECT TOP 1 num_value FROM CTE_Table  WHERE SelRow >= RAND() * (SELECT MAX(SelRow) FROM CTE_Table)
)
Endri
quelle
-1

Zufällige Funktionen aus dem SQL könnten helfen. Auch wenn Sie sich auf nur eine Zeile beschränken möchten, fügen Sie diese am Ende hinzu.

SELECT column FROM table
ORDER BY RAND()
LIMIT 1
nvnvashisth
quelle