2

random() による並べ替えが、ランダムな行を取得する最悪の方法であることは既に知っています。random_number 列を追加し、ランダムな行を取得するときにその列を使用するソリューションを実装し、取得するたびに random_number を更新します。これはすべて、ランダムなプロキシ IP を返すサービスに参加するために使用されます。

select proxy_ip from proxy where random_number > 0.63 limit 1

0.63 は、アプリケーション内で生成される乱数の一例です。

問題は、「最悪の」ソリューションを使用する場合です。

select proxy_ip from proxy
order by random()
limit 1

サービスが呼び出されると、より高速に実行されるように見えます。sort by random()テーブルには 9300 行が含まれているので、私の質問は、最悪のソリューションを作成するには、テーブルに何行含める必要があるかということです。

アプリケーションには、db で直接動作しないオーバーヘッドが少し発生します。代わりに、クエリを実行するデータ層を使用します。これにより、より優れたソリューションの実行速度が遅くなる理由が少し説明されます (さらに、1 つのクエリを実行しますrandom_number を更新する必要があるため、1 だけではありません)。

Explain Analyst の結果:

ランダムに並べ替え()

Limit  (cost=837.03..837.03 rows=1 width=18) (actual time=34.954..34.956 rows=1 loops=1)
  ->  Sort  (cost=837.03..860.46 rows=9373 width=18) (actual time=34.950..34.950 rows=1 loops=1)
        Sort Key: (random())
        Sort Method: top-N heapsort  Memory: 25kB
        ->  Seq Scan on proxy  (cost=0.00..790.16 rows=9373 width=18) (actual time=0.013..17.951 rows=9363 loops=1)
Total runtime: 34.993 ms

ランダム列の使用:

Limit  (cost=0.00..0.23 rows=1 width=18) (actual time=0.038..0.045 rows=1 loops=1)
  ->  Seq Scan on proxy  (cost=0.00..790.16 rows=3481 width=18) (actual time=0.029..0.029 rows=1 loops=1)
        Filter: (random_number > 0.63::double precision)
Total runtime: 0.078 ms

テーブルには 1 つのインデックスがあります。

CREATE UNIQUE INDEX proxy_pkey ON proxy USING btree (id)
4

2 に答える 2

1

この投稿を参照してくださいpostgreSQLテーブルからランダム化されたデータ行を取得する方法は?

これは、トラックにたくさんの素晴らしい情報がある、本当に明るいPostgresの人(Depesz)のサイトにリンクしています。->ランダムな行を取得することについての私の考えをDepesz

この情報を使用して、いくつかの異なる方法を試して、何が最も効果的かを確認してください。

于 2012-12-12T20:25:17.963 に答える
1

いろいろ考え...

  1. あなたの質問への答えは、ハードウェアと実装に非常に固有のものになります。9300 行は、最新のハードウェアではあまり多くありません。最初の読み取りの後、テーブル全体がメモリに格納される可能性があります。したがって、後続のORDER BY RANDOM()クエリは非常に高速になります。

  2. また、その列にインデックスを付けないことで、乱数列のパフォーマンスが低下しています。つまり、テーブル全体を読み取る必要がないように、基本的にテーブル全体を読み取る必要があります。

    したがって、random_number 列にインデックスを追加して、それがどのように役立つかを確認してください。

  3. 次のような方法で更新と選択を同時に行うことで、必要な往復の回数を減らすこともできます。

    UPDATE proxy
    FROM (
        SELECT id 
        FROM proxy
        ORDER BY random_number
        LIMIT 1
    ) AS r
    SET random_number=RANDOM()
    WHERE proxy.id=r.id
    RETURNING proxy.*
    
  4. この方法では、プロキシ サーバーを真にランダム化していません。AE という 5 つのサーバーがあり、最初に 1 ~ 5 の random_numbers が割り当てられたとします。

    A: 1
    B: 2
    C: 3
    D: 4
    E: 5
    

    最初の実行では、random_number が 1 のサーバー A を選択します。次に、新しい乱数 1 ~ 5 を割り当てます。あなたが3を得るとしましょう:

    B: 2
    C: 3
    A: 3
    D: 4
    E: 5
    

    2 回目の実行で、B を取得し、それに新しい乱数、たとえば 4 を割り当てます。

    C: 3
    A: 3
    D: 4
    B: 4
    E: 5
    

    次に C を取得し、それに新しい乱数 2 を与えます。

    C: 2
    A: 3
    D: 4
    B: 4
    E: 5
    

    一部のサーバーがどのように枯渇するかは簡単にわかるはずです...リストの最後に表示されるほど「不運な」サーバーは、おそらく永遠にそこにとどまります.

  5. はるかに優れた、実際にはランダムなアプローチは、各サーバーに指定された範囲内の静的な番号を割り当て、その番号をランダムに (またはハッシュを使用して疑似ランダムに) 選択することです。大量の書き込みを行っていないため、これはパフォーマンスに優れており、実際にはランダムです!

    SELECT proxy_ip
    FROM proxy 
    WHERE id=(RANDOM()*9300)::INT
    
于 2012-12-13T08:55:02.917 に答える