我目前正在PHP构建一个脚本,当它完成它的目的时必须更新统计信息。该脚本由Web浏览器访问,并且可以根据流量同时执行。我必须保证统计数据是正确的。
为了给你拍照,让我们说我们有一张桌子:
CREATE TABLE statistics(
user_id integer NOT NULL,
date integer NOT NULL, -- for unix time
stat1 integer NOT NULL DEFAULT 0,
stat2 integer NOT NULL DEFAULT 0,
stat3 integer NOT NULL DEFAULT 0 -- and so on...
);
-- Let's insert some testing data for a couple of users and days...
-- Day one
INSERT INTO statistics(1, 1303520820, 1, 1, 1);
INSERT INTO statistics(2, 1303520820, 1, 1, 1);
-- Day two
INSERT INTO statistics(1, 1303603200, 1, 1, 1);
INSERT INTO statistics(2, 1303603200, 1, 1, 1);
-- Day three
INSERT INTO statistics(1, 1303689600, 1, 1, 1);
INSERT INTO statistics(2, 1303689600, 1, 1, 1);
每天在表格中插入一个新行,这样我们就可以获得每日,每周,每月,每年的统计数据。我必须确保每天 user_id 只插入一行。此外,每当执行UPDATE查询时,它都会适当地增加列 stat1 , stat2 , stat3 。
这个脚本应该有相当多的流量,我想弄清楚如何在执行脚本时让事情工作并且有几个实例同时工作。您最适合这些任务的方法/技术是什么?
答案 0 :(得分:3)
最简单的解决方案是添加唯一约束
CREATE TABLE statistics(
user_id integer NOT NULL,
date integer NOT NULL, -- for unix time
stat1 integer NOT NULL DEFAULT 0,
stat2 integer NOT NULL DEFAULT 0,
stat3 integer NOT NULL DEFAULT 0, -- and so on...
UNIQUE(user_id,date)
);
无论你采取什么其他措施,你都应该这样做。
答案 1 :(得分:1)
正如其他人所说,你需要对user_id和date这一对的唯一约束。
为了在复合键(user_id,date)不存在时不进行算术运算,并且当复合键 存在时用算术更新,则需要编写一些代码。非正式地,这被称为“upsert”。不止一种方式。
PosgreSQL docs有一个函数示例,它使用异常处理来实现这种要求。函数的问题在于,您无法强制应用程序代码或数据库女孩每次都使用它,毫无例外。
你可以(我认为)使用suppress_redundant_updates_trigger()。触发器的优点是它们不能被应用程序代码或数据库女孩意外绕过。我自己没有使用过这种技术,所以我无法对此进一步评论。此触发器记录在here。
答案 2 :(得分:1)
此外,您可以添加CHECK日期值以确保它是1天的倍数:
ALTER TABLE "statistics" ADD CONSTRAINT "1day_quantum" CHECK ("date" = ("date" / 86400)::INTEGER * 86400);
如果尝试插入错误的日期值,则会抛出异常。
如果日期字段类型为TIMESTAMP或TIMESTAMPTZ,则CHECK更复杂:
ALTER TABLE "statistics" ADD CONSTRAINT "1day_quantum" CHECK ("date" = TIMESTAMP 'epoch' + ((EXTRACT(EPOCH FROM "date") / 86400)::INTEGER * 86400) * INTERVAL '1 second');
通过更改86400(秒计数),您可以将约束调整为各种量程:900例如15分钟。