PostgreSQL重用更新计算

时间:2013-11-11 18:36:29

标签: postgresql sql-update query-optimization

我有一个用于跟踪用户在游戏中的进度的表格,如下所示:

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

我想创建一个查询,它将通过以下方式更新用户的进度:

  • 添加一定数量的尝试
  • 添加一定数量的更正
  • 重新计算准确度(作为衰减平均值)
  • 重新计算状态(基于新的准确度)

现在,前三个点可以通过以下方式轻松实现:

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会在内部进行优化吗?

1 个答案:

答案 0 :(得分: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之间的玩家,但状态似乎不必要地存储与行数一样多的字符串。)