sql >> データベース >  >> RDS >> Mysql

単一のクエリでwhereフィルターを使用して30kのMySQLテーブルから3つのランダムレコードをすばやく選択するにはどうすればよいですか?

    醜いですが、迅速かつランダムです。特に以下で説明するチューニングでは、非常に醜くなり、非常に速くなる可能性があるため、この方法で本当に必要なことを確認してください。

    (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行がフェッチされるという保証はまだありません。可能性が高くなるだけです。



    1. MariaDB/MySQLデータベースのSQLDependency

    2. MySQL追加外部キー

    3. PostgreSQLでのDiv()のしくみ

    4. SQLでサブクエリを再利用する方法は?