1

次のようなゲームでのユーザーの進行状況を追跡するためのテーブルがあります。

create table progressions (
  user_id       int,
  attempt_count int,
  correct_count int,
  accuracy      float,
  state         text
);

次の方法でユーザーの進行状況を更新するクエリを作成したいと考えています。

  • 試行回数を追加する
  • 一定数の正解を追加
  • 精度を再計算します (減衰平均として)
  • 状態を再計算する (新しい精度に基づく)

さて、最初の 3 つのポイントは、次のような方法で簡単に達成できます。

update
  progressions p
set
  attempt_count = p.attempt_count + {attempt_count},
  correct_count = p.correct_count + {correct_count},
  accuracy      = p.accuracy * (1 - {alpha}) + ({correct_count} / {attempt_count}::float) * {alpha}
where
  user_id       = {user_id};

問題は、精度に基づいて状態を更新したいときに発生します。ここでは、条件で精度式の結果を再利用する必要があります。

  ...
  accuracy = {accuracy_expression},
  state    = case
    when {accuracy_expression} > 0.9 then 'exceptional'
    when {accuracy_expression} > 0.8 then 'pretty good'
    ...
  end
  ...

この状況で CTE を使用できると思います (アトミック性の影響の可能性があります) が、再計算せずに精度式の結果を再利用する方法が他にあるのでしょうか?

そうでない場合、これを何回も繰り返した場合、PostgreSQL が内部的に最適化するものNですか?

4

1 に答える 1

1

代わりに、更新前のトリガーでこれらの計算フィールドを維持することを検討しましたか?

create function progressions_accuracy_upd() returns trigger as $$
begin
  new.state := case
    when new.accuracy > 0.9 then 'exceptional'
    when new.accuracy > 0.8 then 'pretty good'
    …
  return new;
end;
$$ language plpgsql;

create trigger progressions_accuracy_upd before update on progressions
for each row when (new.accuracy is distinct from old.accuracy)
execute procedure progressions_accuracy_upd();

さらに言えば、アプリで状態フィールドを直接計算することを検討したことはありますか? (accuracy フィールドは、精度が x と y の間のプレーヤーを照会するために、より理にかなっていますが、state は行と同じ数の文字列を不必要に格納しているように見えます。)

于 2013-11-11T20:14:55.390 に答える