醜いですが、迅速かつランダムです。特に以下で説明するチューニングでは、非常に醜くなり、非常に速くなる可能性があるため、この方法で本当に必要なことを確認してください。
(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)
最初の行が必要以上に頻繁に表示されます
テーブル内のID間に大きなギャップがある場合、そのようなギャップの直後の行は、このクエリによってフェッチされる可能性が高くなります。場合によっては、本来よりもかなり頻繁に表示されます。これは一般的に解決することはできませんが、一般的な特定のケース(0とテーブル内の最初の既存のIDの間にギャップがある場合)の修正があります。
サブクエリの代わりに(SELECT RAND()*<max_id> AS ID)
(SELECT <min_id> + RAND()*(<max_id> - <min_id>) AS ID)
のようなものを使用します
重複を削除
クエリをそのまま使用すると、重複する行が返される場合があります。 UNION
を使用することで、これを回避できます。 UNION ALL
の代わりに 。この方法で重複がマージされますが、クエリは正確に3行を返すことを保証しなくなります。必要以上の行をフェッチし、次のように外部結果を制限することで、これを回避することもできます。
(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3
ただし、3行がフェッチされるという保証はまだありません。可能性が高くなるだけです。