2017-05-04 5 views
0

説明のために、テーブルProductOffersとその価格を更新しています。この表の変更点は、新しいProductOfferの追加、既存のProductOfferの価格の変更です。トリガプロシージャで集計テーブルを更新して、適切な並行処理を行う方法はありますか?

上記の変更に基づいて、すべてのオファーに対して集計された商品ごとの価格情報を保持する商品表を更新したいと思います。

これは、行ベースの更新/挿入トリガを使用して実装するのが理にかなっています。トリガは、Product行を作成/更新するプロシージャを実行します。

私は、同時更新(したがってトリガー)を適切に実装したいと思います。つまり、同じ製品のproductOffersを同時に更新すると、複数のトリガされたプロシージャが同時に同じProduct行を挿入/更新しようとするため、誤った集計値につながる可能性があります。

私は行ベースのロックを使用できません。 (つまり、select .. for update)特定の製品列が既に存在することが保証されていないためです。その代わりにProductOfferがプロシージャをトリガーすると、(更新されるのではなく)Product行の周りに初めて作成する必要があります。 Afaik、行ロックは挿入される新しい行では機能しません。これは完全に意味があります。

だから私はどこにいますか?自分の楽観的なロックスキームをロールバックする必要がありますか?これには、次のものを含める必要があります:

  • チェック行が存在しない=>新しい行がすでに存在すれば失敗します。 (2つのトリガーが並行して行を作成しようとすると可能です)。後で更新して再試行してください。
  • チェック行が存在し、バージョン= x =>行を更新しますが、row.version!= xの場合は失敗します。その後にもう一度お試しください

上記の作業、またはより優れた/すぐに使えるソリューションはありますか?将来の参照のために

EDITはまさに私が達成したいものを示して公式の例を見つけました:Example 39-6. A PL/pgSQL Trigger Procedure For Maintaining A Summary Table

+0

いくつかの利用可能なロック(テーブルロックなど)のうちの1つ –

+0

はい、行レベルのロックが疑問に思われるので、完全なテーブルロックを必要としますか?これにより、パフォーマンスが大幅に向上します。このテーブルで約500回/秒の更新を探していますが、これはテーブルロックを使用すると元に戻すことができますか? –

+1

まず、列など(バージョンなど)を使用して独自のロック方式をロールバックする必要はありません。 集計行が「製品」であり、同じ製品内の他のアイテムのみを考慮する必要がある場合は、アドバイザリロックを使用して、特定の製品が現在再計算されていることを他のトランザクションに知らせることができます行を追加する前に製品がロックされていません。これにより、テーブル単位ではなく製品ごとに処理が遅くなり、役立つ可能性があります。 –

答えて

0

物事は、ACID私のおかげで、あなたは彼らが考えるよりはるかに簡単です。

想定されるトリガーは、トリガーされたデータ変更と同じトランザクションで実行され、アグリゲートテーブルを変更するたびに、更新する行が最初にEXCLUSIVEのロックでロックされます。

したがって、2つの並行トランザクションによって集計テーブル内の同じ行にUPDATEがある場合、最初のトランザクションはロックを取得して処理を進め、2番目のトランザクションは最初のトランザクションがコミット(またはロールバック)行のロックを取得して変更することができます。

したがって、集計テーブル内の同じ行を更新するデータの変更は効果的にシリアル化されるため、パフォーマンスが低下する可能性がありますが、正確な結果が保証されます。

+0

これは意味がありますが、行がまだ存在せず、2つのトリガーが同じ製品の行を作成しようとするとどうなりますか? –

+1

同じ製品の2つの行を禁止するユニーク制約を作成し、 'INSERT ... ON CONFLICT ... UPDATE'を使用します。 –

関連する問題