我正在探索触发器,并希望创建一个在
game_saved
列上的更新事件后触发的触发器。正如我在PostgreSQL文档中读到的那样,可以为列创建触发器。该列包含 boolean
值,因此用户可以将游戏添加到他的收藏中或将其删除。所以我希望触发函数计算某个用户在 game_saved
列中设置为 TRUE 的游戏数量。然后在 total_game_count
表中更新 game_collection
。
game_collection
id - BIGSERIAL primary key
user_id - INTEGER REFERENCES users(id)
total_game_count - INTEGER
game_info
id - BIGSERIAL primary key
user_id - INTEGER REFERENCES users(id)
game_id - INTEGER REFERENCES games(id)
review - TEXT
game_saved - BOOLEAN
这是我的触发器(它不起作用,我想找出原因):
CREATE OR REPLACE FUNCTION total_games()
RETURNS TRIGGER AS $$
BEGIN
UPDATE game_collection
SET total_game_count = (SELECT COUNT(CASE WHEN game_saved THEN 1 END)
FROM game_info WHERE game_collection.user_id = game_info.user_id)
WHERE user_id = NEW.user_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_total_games
AFTER UPDATE OF game_saved FOR EACH ROW
EXECUTE PROCEDURE total_games();
如果我将
AFTER UPDATE OF game_saved
(列)更改为 AFTER UPDATE ON game_info
(表),触发器将正常工作。因此,专门为列更新创建触发器存在一些问题。
在列更新时触发触发器是个好主意还是我应该在这里寻找另一种方法?
语法如下(如手册中所述):
CREATE TRIGGER tr_total_games
AFTER UPDATE OF game_saved ON game_info
FOR EACH ROW
EXECUTE FUNCTION total_games();
对于 Postgres 10 或更早版本,请使用:
...
EXECUTE PROCEDURE total_games();
参见:
但整个方法是值得怀疑的。通过触发器保持聚合最新很容易在并发写入负载下出现错误。
在没有并发写入负载的情况下,还有更简单的解决方案:只需从当前总数中加/减 1 ...
VIEW
将是一个可靠的选择。完全删除列game_collection.total_game_count
- 也许还有整个表game_collection
,这似乎没有任何其他目的。创建一个 VIEW
来代替:
CREATE VIEW v_game_collection AS
SELECT user_id, count(*) AS total_game_count
FROM game_info
WHERE game_saved
GROUP BY user_id;
这将返回
game_info
中至少有 1 行的所有用户,其中 game_saved IS TRUE
(并忽略所有其他)。
MATERIALIZED VIEW
或相关解决方案来提高读取性能。这是性能、存储/缓存占用空间和最新状态之间的权衡。