Ich habe eine Datenbank von ungefähr 8 Millionen plus Zeilen, aus denen ich zufällig n Zeilen auswählen möchte. Zuallererst habe ich die populäre und ähnliche Frage hier auf StackOverflow
Die angebotenen Lösungen funktionieren gut, wenn ich einen bestimmten Prozentsatz der Zeilen ohne zusätzliche Bedingungen zufällig ausgewählt haben möchte. Aber was ich n Zeilen zufällig auswählen möchte (z. B. höchstens 5 Zeilen), die alle eine bestimmte Bedingung erfüllen.
Meine Datenbank enthält Wörter mit Informationen wie Wortart, Tag, Lemma und Token. Jetzt möchte ich eine Abfrage durchführen, um 5 zufällige Wörter auszuwählen, die alle dem Wort in der Abfrage ähnlich sind (z. B. gib mir 5 Wörter ähnlich wie fuzzy ), dies wird bestimmt, indem nur Wörter mit demselben Teil betrachtet werden Sprache und ein Wert der Levenshtein-Distanz über einer bestimmten Schwelle. Ich habe eine Funktion in SQL Server, die die Levenshtein Entfernung berechnen kann.
Das Problem mit den oben genannten Methoden ist, dass sie entweder alle Datensätze durchlaufen und die Levenshtein-Distanz berechnen müssen (was viel Zeit in Anspruch nimmt) oder sie bieten mir nur an, einen Prozentsatz anstelle von n Zeilen auszuwählen / p>
Eine Abfrage, die ausreichend funktioniert, ist:
%Vor%Aber mit nur Top bekomme ich immer die gleichen Ergebnisse. Ich brauche mein Top, um zufällig zu sein. Methoden wie die Verwendung von NEWID () gehen zuerst über die gesamte Datenbank und dann nach dem Zufallsprinzip, was nicht mein beabsichtigtes Verhalten ist, da sie viel zu lange dauern.
Hat jemand eine Idee, n zufällige Reihen schnell auf einer riesigen Datenbank auszuwählen?
BEARBEITEN:
Jemand (nicht auf StackOverflow) hat mir möglicherweise eine Lösung mit der OPTION -Klausel und dem schnellen -Schlüsselwort angeboten, die die ersten n gefundenen Zeilen abruft.
Mit der OPTION (schnell 5) erziele ich die bisher beste Leistung (10 Sekunden auf einer 8 Millionen-Zeilen-Tabelle). Ich änderte auch die Levenshtein-Funktion von einer SQL-Implementierung in eine c # geschriebene Bibliotheksimplementierung, die die Leistung erheblich beschleunigte.
%Vor%Es wird schwierig, einen vollständigen Scan zu vermeiden. Wenn Sie eine Spalte haben, die Sie leicht zufällig auswählen könnten, wenn Sie zum Beispiel eine "dichte" Identitätsspalte mit wenigen Lücken haben, ersetzen Sie Klarks Ansatz mit der folgenden Änderung:
%Vor%Um zufällige Daten zu erhalten, müssen Sie alle Zeilen durchlaufen, die Ihrer where-Klausel entsprechen. Die Suche wird nur in den Zeilen ausgeführt, die Ihrem where-Ausdruck entsprechen, so dass es nicht die vollständige Tabellensuche ist. Wenn Sie viele Datensätze haben, die Ihrer Suche entsprechen, können Sie Folgendes tun:
%Vor%Aber natürlich wird das nicht wirklich zufällig sein.
Aus Ihrer Frage gehe ich davon aus, dass Sie wissen, dass viele Zeilen Ihrer Bedingung edit_distance > 0.5
entsprechen. Aber SQL Server weiß das nicht. Eine Möglichkeit, diese Informationen mit SQL Server zu teilen, besteht darin, eine explizitere Abfrage mithilfe von Tabellenvariablen zu schreiben.
Das obige Snippet wählt jeweils 100 zufällige Zeilen aus und fügt diejenigen ein, die in die Ergebnistabelle passen. Es läuft so lange, bis es 5 Zeilen gefunden hat. Am Ende wählt es 5 Zeilen aus der Ergebnistabelle.
Dies sollte effizienter sein, wenn Sie viele übereinstimmende Zeilen haben, aber viel weniger effizient, wenn es nur wenige gibt.
Ich denke, es gibt eine fundamentale Grenze dafür, wie schnell Sie das tun können, wonach Sie suchen. Wenn Sie schnell Datensätze aus der Tabelle auswählen möchten, müssen Sie einen Index verwenden. Nehmen wir an, Sie haben eine sequentielle Integer-Spalten-ID und es handelt sich um den Clustered-Index: Sie könnten Datensätze mit bestimmten zufälligen ID-Werten auswählen, aber Sie haben keine Garantie, dass jede ID zwischen MIN (ID) und MAX (ID) Ihnen eine Zeile eingibt Die Tabelle, so dass Sie am Ende mit weniger Zeilen enden können, als Sie verlangten.
Eine Sache, die Sie tun könnten, ist die Abfrage, die die Bedingungen hat, die Sie anwenden möchten, und fügen Sie eine Zeilennummer hinzu (siehe dieser Technet-Artikel ) und dir somit einen sequenziellen "Schlüssel" gibt, der keine "Löcher" enthält ... wähle Zufallszahlen innerhalb der Grenzen dieses Schlüssels. Sie werden dann mit einer Teilmenge der Tabelle und nicht mit der ganzen Tabelle zu tun haben, aber ich vermute, dass dies möglicherweise das Beste ist, was Sie leistungsmäßig tun können.
Sie könnten mit "Löchern" in der ID umgehen, indem Sie eine Tabellenwertfunktion schreiben, die eine Schleife verwendet (wählen Sie einfach zufällige Werte, bis Sie die gewünschte Anzahl an Ergebnissen erhalten), aber das ist unelegant und könnte Probleme mit der Nebenläufigkeit haben Zugriffsmuster auf Ihre Datenbank. Es kommt also auf Ihre Anforderungen an.
Tags und Links sql sql-server random performance query-performance