Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann man schnell 3 zufällige Datensätze aus einer 30k-MySQL-Tabelle mit einem Where-Filter durch eine einzige Abfrage auswählen?

Hässlich, aber schnell und zufällig. Kann sehr schnell sehr hässlich werden, besonders mit der unten beschriebenen Abstimmung, also stellen Sie sicher, dass Sie es wirklich so wollen.

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

Die erste Zeile erscheint öfter als sie sollte

Wenn Sie große Lücken zwischen den IDs in Ihrer Tabelle haben, haben Zeilen direkt nach solchen Lücken eine größere Chance, von dieser Abfrage abgerufen zu werden. In manchen Fällen treten sie deutlich häufiger auf, als sie sollten. Dies kann nicht allgemein gelöst werden, aber es gibt eine Lösung für einen häufigen Sonderfall:wenn es eine Lücke zwischen 0 und der ersten vorhandenen ID in einer Tabelle gibt.

Statt Unterabfrage (SELECT RAND()*<max_id> AS ID) Verwenden Sie so etwas wie (SELECT <min_id> + RAND()*(<max_id> - <min_id>) AS ID)

Duplikate entfernen

Die Abfrage kann, wenn sie unverändert verwendet wird, doppelte Zeilen zurückgeben. Dies kann durch die Verwendung von UNION vermieden werden statt UNION ALL . Auf diese Weise werden Duplikate zusammengeführt, aber die Abfrage garantiert nicht mehr, genau 3 Zeilen zurückzugeben. Sie können das auch umgehen, indem Sie mehr Zeilen abrufen, als Sie benötigen, und das äußere Ergebnis wie folgt einschränken:

(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3

Es gibt jedoch immer noch keine Garantie dafür, dass 3 Zeilen abgerufen werden. Es macht es nur wahrscheinlicher.