3

私はPHPでPostgreSQLに取り組んでいます。

列FROMテーブルWHERE条件で特定の数のランダム値を選択することは可能ですか?

それ以外の

を選択FROMテーブルWHERE条件

次に、それらを配列に変換して使用しarray_rand()ますか?

array_rand()(何百万もの行があり、最初にすべての値を選択するとおそらく時間がかかるため、この方法は使用したくありません。)


次のようなテーブルがあるとします。

   name    |   items
-----------+------------
    Ben    | {dd,ab,aa}  
-----------+------------
   David   |  {dd,aa}  
-----------+------------
   Bryan   | {aa,ab,cd}
-----------+------------
    Glen   |    {cd}
-----------+------------
   Edward  |   {aa,cd}
-----------+------------
   Aaron   |  {dd,aa}
-----------+------------
  ..... (many many more)

アップデート:

@> ARRAY[aa]そして、シーケンシャル テーブル スキャンや時間のかかるものを使用せず に、条件 (この場合は ) に一致する列 (または基本的には 10 個のランダム行) 内の 10 個のランダムな値を選択する必要があります。

order by random()すべての行を処理する必要があるため、多くの時間がかかるため、代わりにより良いソリューションを使用します。

4

2 に答える 2

5

PostgreSQLではできるorder by random()ので、これはあなたが望むものになるはずです:

select name
from table
where items @>ARRAY['aa']
order by random()
limit 10;
于 2012-04-13T13:58:19.107 に答える
1

このソリューションは、ベーステーブルが大幅に更新されていない場合に適しています。それ以外の場合、保守コストは利益を超える可能性があります。

条件が常に@> ARRAY[aa]である場合は、補助ルックアップテーブル(基本的にマテリアライズドビュー)を作成できます。

CREATE TABLE tbl_pick (rn serial, id int, PRIMARY KEY (rn, id);

INSERT INTO tbl_pick (id)
SELECT id FROM tbl
WHERE  items @> ARRAY[aa];

次に、ここで説明するのと同様の方法を適用できます。

SELECT *
FROM  (
    SELECT 1 + floor(random() * <insert_count_plus_a_bit_here>)::integer AS rn
    FROM   generate_series(1, 20) g
    GROUP  BY 1                     -- trim duplicates
    ) r
JOIN   tbl_pick USING (rn)
JOIN   tbl USING (id)
LIMIT  10;                          -- trim surplus

これは非常に高速である必要があります。これは、インデックススキャンのみが必要であり、テーブルから読み取られるのは最大10行のみであるためです。

もちろん、tbl_pick(関連する)INSERT / DELETE/UPDATEの後に更新する必要がありますtbl。メソッドには多少の余裕があるため、少数の更新をtbl_pickに追加/削除(更新なし)することができます。一定数の更新の後TRUNCATE、完全なを再実行しINSERTます。基本的に、マテリアライズドビューを書き直します。

tbl_pickUPDATEとDELETEは、。を使用した外部キ​​ー制約を使用してカスケードできますON UPDATE CASCADE ON DELETE CASCADEAFTER INSERTそして、新しく挿入された行のトリガー。それはすべて、ベーステーブルで何が可能かによって異なります。

また、tbl_pickの完全な書き換えを定期的に、できれば営業時間外にスケジュールします。

ランダム選択クエリがバーストで発生する場合は、(fk制約とトリガーの代わりに)ダーティかどうかを示す「変数」をtbl_pick用意し、クエリを実行する前に(複数回)そのような場合にのみテーブルを補充する方が安価な場合があります。これは、使用パターンによって大きく異なります。この「変数」は、1行のテーブルである可能性がありますUPDATE。(関連する)をに更新した後はTRUEに設定しtbl、マテリアライズド・ビューをリフレッシュした後はFALSEに設定します。

于 2012-04-14T04:41:35.927 に答える