MySQL 1つのクエリでランダムな文字列を選択する

何がありますか?



弱いラップトップ、数百万行のテーブルがあり、1つのクエリで異なる数のランダムな行を選択する必要があります。 それ以上のサンプルは興味がありません。



テーブル(テスト)の構造は次のとおりです。



主キーにがなく1から始まります。



生産方法



  1. RAND + LIMITで並べ替え


    画像



    1行取得:

    SELECT pk_id FROM test ORDER BY rand() LIMIT 1
          
          





    MySQLの平均リードタイムは6.150秒です



    100エントリを取得してみましょう

     SELECT pk_id FROM test ORDER BY rand() LIMIT 100
          
          





    平均リードタイム6.170-6.180秒

    つまり、1〜100個のランダムな文字列を取得する時間差は重要ではありません。



  2. COUNT * rand()


    画像



    1行取得:

     SELECT t.pk_id FROM test as t, (SELECT ROUND(COUNT(pk_id)*rand()) as rnd FROM test LIMIT 1) t WHERE t.pk_id = rnd
          
          





    を使用して
     ROUND(COUNT(pk_id)*rand())
          
          



    0からテーブル内の行数までの乱数を取得します。

    次に、エイリアス「rnd」を乱数に割り当て、pk_idと同等の比較のためにWHEREで使用します。

    平均リードタイム-1.04秒

    次に、この要求をわずかに変更して、複数の行を拡張できるようにする必要があります。

    いくつかのフィールドをサブクエリに追加し、WHEREのチェックを「=」から「IN」に変更します

     SELECT t.pk_id FROM test as t, (SELECT ROUND(COUNT(pk_id)*rand()) as rnd, ROUND(COUNT(pk_id)*rand()) as rnd2, ROUND(COUNT(pk_id)*rand()) as rnd3 FROM test LIMIT 1) t WHERE t.pk_id IN (rnd,rnd2,rnd3)
          
          





    平均リードタイムは1.163秒です。

    受信する行数が増えると、クエリの実行時間が大幅に増加します。

    約100行、考えるのも怖いです:)



  3. INFORMATION_SCHEMA + LIMIT


    画像



    1行取得:

     SELECT t.pk_id FROM test as t, (SELECT ROUND((SELECT table_rows as tr FROM information_schema.tables WHERE table_name = 'test') *rand()) as rnd FROM test LIMIT 1) tmp WHERE t.pk_id = rnd
          
          





    サブクエリを使用して、集計関数COUNTを使用せずにテーブル 'test'の行数を取得し、方法2と同様にさらに比較を行います。

    平均リードタイム-0.042秒

    最小実行時間は0.003秒です。

    100行を取得してみましょう。

     SELECT t.pk_id FROM test as t, (SELECT ROUND((SELECT table_rows as tr FROM information_schema.tables WHERE table_name = 'test') *rand()) as rnd FROM test LIMIT 100) tmp WHERE t.pk_id in (rnd) ORDER BY pk_id
          
          





    WHERE "="をINに変更し、サブクエリによって返される行の制限を100に変更します。

    平均リードタイム-0.047秒

    1000レコードを取得する時間-0.053秒

    10,000レコードを取得する時間〜0.21秒

    最後に、 1.9秒で 100,000レコードを取得します

    このアプローチの欠点は 、INFORMATION_SCHEMAからの結果の行数がCOUNT(*)よりわずかに大きいため、100,000行を返すときに7〜8行が失われることです。 1〜100では、これは実質的にありません(テーブルが大きいほど、チャンスは少なくなります)。 しかし、あなたはいつでも再保険のためにさらに1-2行を取ることができます:)



  4. MAX * rand()


    1行取得:

     SELECT t.pk_id FROM test as t, (SELECT ROUND((SELECT MAX(pk_id) FROM test) *rand()) as rnd FROM test LIMIT 1) tmp WHERE t.pk_id = rnd
          
          





    平均リードタイム-0.001秒

    100行の取得:

     SELECT t.pk_id FROM test as t, (SELECT ROUND((SELECT MAX(pk_id) FROM test) *rand()) as rnd FROM test LIMIT 100) tmp WHERE t.pk_id in (rnd) ORDER BY pk_id
          
          





    平均リードタイム-0.003秒



    前の方法に比べて、最速の方法。





結論







UPD:テーブルの穴の場合、2番目と3番目の方法で1つの行を返すとき、同等ではないチェックを行うことができますが、> =を追加し、LIMIT 1を追加します。

このコメントをありがとう。

UPD2: 4つの受信方法を追加しました。 アイデアをありがとう。



All Articles