Ich möchte meine Abfragen optimieren, damit ich sie mir ansehen kann mysql-slow.log
.
Die meisten meiner langsamen Abfragen enthalten ORDER BY RAND()
. Ich kann keine echte Lösung finden, um dieses Problem zu lösen. Theres ist eine mögliche Lösung bei MySQLPerformanceBlog, aber ich denke nicht, dass dies genug ist. Bei schlecht optimierten (oder häufig aktualisierten, vom Benutzer verwalteten) Tabellen funktioniert dies nicht oder ich muss zwei oder mehr Abfragen PHP
ausführen, bevor ich meine generierte Zufallszeile auswählen kann .
Gibt es eine Lösung für dieses Problem?
Ein Dummy-Beispiel:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
ORDER BY
RAND()
LIMIT 1
mysql
random
performance
fabrik
quelle
quelle
Antworten:
Versuche dies:
Dies ist besonders effizient
MyISAM
(da diesCOUNT(*)
sofort geschieht), aber selbst in Zeiten, in denenInnoDB
es10
effizienter ist alsORDER BY RAND()
.Die Hauptidee hier ist, dass wir nicht sortieren, sondern zwei Variablen behalten und die
running probability
einer Zeile berechnen, die im aktuellen Schritt ausgewählt werden soll.Weitere Informationen finden Sie in diesem Artikel in meinem Blog:
Aktualisieren:
Wenn Sie nur einen einzelnen zufälligen Datensatz auswählen müssen, versuchen Sie Folgendes:
Dies setzt voraus, dass Ihre
ac_id
mehr oder weniger gleichmäßig verteilt sind.quelle
@fabrik
: Versuche es jetzt. Es wäre sehr hilfreich, wenn Sie die Tabellenskripte veröffentlichen würden, damit ich sie vor dem Posten überprüfen könnte.Es hängt davon ab, wie zufällig Sie sein müssen. Die von Ihnen verknüpfte Lösung funktioniert IMO ziemlich gut. Sofern Sie keine großen Lücken im ID-Feld haben, ist es immer noch ziemlich zufällig.
Sie sollten dies jedoch in einer Abfrage tun können (um einen einzelnen Wert auszuwählen):
Andere Lösungen:
random
der Tabelle ein permanentes Float-Feld hinzu und füllen Sie es mit Zufallszahlen. Sie können dann eine Zufallszahl in PHP generieren und tun"SELECT ... WHERE rnd > $random"
quelle
SELECT [fields] FROM [table] WHERE id >= FLOOR(RAND()*(SELECT MAX(id) FROM [table])) LIMIT 1
aber dies scheint nicht richtig zu funktionieren, da es nie den letzten Datensatz zurückgibtSELECT [fields] FROM [table] WHERE id >= FLOOR(1 + RAND()*(SELECT MAX(id) FROM [table])) LIMIT 1
Scheint den Trick für mich zu tunSo würde ich es machen:
quelle
OFFSET
die Verwendung (wofür@r
) wird ein Scan nicht vermieden - bis zu einem vollständigen Tabellenscan.(Ja, ich werde mich ärgern, weil ich hier nicht genug Fleisch habe, aber kannst du nicht einen Tag lang Veganer sein?)
Fall: Aufeinanderfolgendes AUTO_INCREMENT ohne Lücken, 1 Zeile zurückgegeben
Fall: Aufeinanderfolgendes AUTO_INCREMENT ohne Lücken, 10 Zeilen
Fall: AUTO_INCREMENT mit Lücken, 1 Zeile zurückgegeben
Fall: Zusätzliche FLOAT-Spalte zum Randomisieren
Fall: UUID- oder MD5-Spalte
Diese 5 Fälle können für große Tische sehr effizient gemacht werden. Siehe meinen Blog für die Details.
quelle
Dadurch erhalten Sie eine einzelne Unterabfrage, die den Index verwendet, um eine zufällige ID abzurufen. Bei der anderen Abfrage wird die verknüpfte Tabelle abgerufen.
quelle
Die Lösung für Ihr Dummy-Beispiel wäre:
Um mehr über Alternativen zu zu
ORDER BY RAND()
erfahren, sollten Sie diesen Artikel lesen .quelle
Ich optimiere viele vorhandene Abfragen in meinem Projekt. Die Lösung von Quassnoi hat mir geholfen, die Abfragen sehr zu beschleunigen! Es fällt mir jedoch schwer, diese Lösung in alle Abfragen zu integrieren, insbesondere bei komplizierten Abfragen, an denen viele Unterabfragen in mehreren großen Tabellen beteiligt sind.
Ich verwende also eine weniger optimierte Lösung. Grundsätzlich funktioniert es genauso wie die Lösung von Quassnoi.
$size * $factor / [accomodation_table_row_count]
berechnet die Wahrscheinlichkeit, eine zufällige Zeile auszuwählen. Der Rand () generiert eine Zufallszahl. Die Zeile wird ausgewählt, wenn rand () kleiner ist oder der Wahrscheinlichkeit entspricht. Dies führt effektiv eine zufällige Auswahl durch, um die Tabellengröße zu begrenzen. Da die Wahrscheinlichkeit besteht, dass weniger als der definierte Grenzwert zurückgegeben wird, müssen wir die Wahrscheinlichkeit erhöhen, um sicherzustellen, dass wir genügend Zeilen auswählen. Daher multiplizieren wir $ size mit einem $ -Faktor (ich setze normalerweise $ factor = 2, funktioniert in den meisten Fällen). Endlich machen wir daslimit $size
Das Problem besteht nun darin, den accomodation_table_row_count zu ermitteln . Wenn wir die Tabellengröße kennen, KÖNNEN wir die Tabellengröße hart codieren. Dies würde am schnellsten laufen, aber offensichtlich ist dies nicht ideal. Wenn Sie Myisam verwenden, ist das Abrufen der Tabellenanzahl sehr effizient. Da ich innodb benutze, mache ich nur eine einfache Zählung + Auswahl. In Ihrem Fall würde es so aussehen:
Der schwierige Teil besteht darin, die richtige Wahrscheinlichkeit zu ermitteln. Wie Sie sehen können, berechnet der folgende Code tatsächlich nur die grobe temporäre Tabellengröße (tatsächlich zu grob!):
(select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
Sie können diese Logik jedoch verfeinern, um eine genauere Annäherung an die Tabellengröße zu erhalten. Beachten Sie, dass es besser ist, Zeilen über- als unterzuwählen. Wenn die Wahrscheinlichkeit zu niedrig eingestellt ist, besteht die Gefahr, dass nicht genügend Zeilen ausgewählt werden.Diese Lösung läuft langsamer als die Lösung von Quassnoi, da die Tabellengröße neu berechnet werden muss. Ich finde diese Codierung jedoch viel einfacher zu handhaben. Dies ist ein Kompromiss zwischen Genauigkeit + Leistung und Codierungskomplexität . Auf großen Tischen ist dies jedoch immer noch weitaus schneller als bei Order by Rand ().
Hinweis: Wenn die Abfragelogik dies zulässt, führen Sie die zufällige Auswahl so früh wie möglich durch, bevor Verknüpfungsvorgänge ausgeführt werden.
quelle
quelle