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つの受信方法を追加しました。 アイデアをありがとう。

Source: https://habr.com/ru/post/J154905/


All Articles