何がありますか?
弱いラップトップ、数百万行のテーブルがあり、1つのクエリで異なる数のランダムな行を選択する必要があります。 それ以上のサンプルは興味がありません。
テーブル(テスト)の構造は次のとおりです。
- -pk_id(主キー)
- -id(異なる数字で埋められたフィールド)
- -値(rand()で埋められたフィールド)
主キーに
は穴
がなく 、
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個のランダムな文字列を取得する時間差は重要ではありません。
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行、考えるのも怖いです:)
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行を取ることができます:)
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秒
前の方法に比べて、最速の方法。
結論
- 最初の方法は、フィールドの穴とその初期値に関係なく、どんな場合でもランダムな文字列を返すという点で優れていますが、最も遅い
- 2番目の方法は、穴のないテーブルではるかに優れています。 最初の方法よりも6倍速く動作します(1行を返す場合)。
- 3番目の方法は、rand()の値が1に近い文字列を失う可能性があるため、ご自身の危険とリスク(非常に重要ではありません)で使用できます。1行を返す速度は、最初の方法と比較して150倍異なります。
100行ではなく99行を返した場合は、サーバーに再度要求を送信できます。 - 4番目の方法は、最速で6000倍高速のORDER BY rand()です。
UPD:テーブルの穴の場合、2番目と3番目の方法で1つの行を返すとき、同等ではないチェックを行うことができますが、> =を追加し、LIMIT 1を追加します。
このコメントをありがとう。
UPD2: 4つの受信方法を追加しました。 アイデアをありがとう。