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.
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;'
AND rand() <= $size * $factor / [accomodation_table_row_count]
LIMIT $size
$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:
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;'
AND rand() <= $size * $factor / (select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
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.