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(可能会影响原子性),但我想知道是否有任何其他方法可以让我重用精度表达式的结果而不重新计算它?

如果不是,如果我重复N多次,PostgreSQL 会在内部优化吗?

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();

而且,就此而言,您是否考虑过直接在您的应用程序中计算状态字段?(准确度字段更有意义,以便查询准确度在 x 和 y 之间的玩家,但状态似乎不必要地存储与行一样多的字符串。)

于 2013-11-11T20:14:55.390 回答