2016-06-23 10 views
3

ためにここで私がやろうとしている何のための擬似コードです:PostgresのSELECT COUNTは... UPDATE

rate_count = SELECT COUNT(id) FROM job WHERE last_processed_at >= ? 

current_limit = rate_limit - rate_count 
if current_limit > 0 
    UPDATE job SET state='processing' 
    WHERE id IN(
    SELECT id FROM job 
    WHERE state='pending' 
    LIMIT :current_limit 
) 

私はそれが並行性の問題を除いて取り組んでいます。同時に複数のセッションから実行すると、両方のセッションがSELECTとなり、同じものが更新されます:(

2番目のクエリは、SELECTサブクエリにFOR UPDATEを追加することでアトミックになりますが、追加できません最初のクエリに対するUPDATE FOR UPDATEが集約関数では使用できませんFOR

がどのように私はこの作品にアトミックトランザクションを作ることができるので、

+1

は '..更新を選択locked'スキップ:http://blog.2ndquadrant.com/what-is-select-skip-locked-for-in-postgresql-9-5/ –

+0

@a_horse_with_no_nameこれは非常に有望です! –

+0

@a_horse_with_no_nameこれは私の問題を解決するのに役立つものではなく、FOR UPDATEをより最適化するだけですが、とにかくそのことに感謝します –

答えて

2

あなたは、サブクエリ内FOR UPDATEを行うことができます?

rate_count := COUNT(id) 
       FROM (
       SELECT id FROM job 
       WHERE last_processed_at >= ? FOR UPDATE 
       ) a; 

このすべてのことを単一のクエリ:

UPDATE job SET state='processing' 
WHERE id IN (
    SELECT id FROM job 
    WHERE state='pending' 
    LIMIT (SELECT GREATEST(0, rate_limit - COUNT(id)) 
     FROM (SELECT id FROM job 
       WHERE last_processed_at >= ? FOR UPDATE) a 
     ) 
)