PostgreSQL表中行的递增值

| 我目前正在用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列。 预计该脚本会有很多流量,我想弄清楚在脚本执行时如何使事情正常进行,并且有几个实例同时工作。您找到最适合此类任务的方法/技术?     
已邀请:
最简单的解决方案是添加唯一约束
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)
);
无论采取什么其他措施,您都绝对应该这样做。     
正如其他人所说,您需要对user_id和date进行唯一约束。 为了在不存在复合键(user_id,日期)的情况下进行插入而不进行算术运算,并在存在复合键的情况下进行算术更新,您需要编写一些代码。非正式地,这称为“ upsert”。有多种方法。 PosgreSQL文档提供了一个使用异常处理实现这种要求的函数示例。函数的问题在于,您不能强制应用程序代码或数据库女孩每次都无一例外地使用它。 您可以(我认为)使用prevent_redundant_updates_trigger()。触发器的优点在于,应用程序代码或数据库女孩不会意外地绕过触发器。我本人还没有使用过这种技术,所以无法对此做进一步评论。此触发器记录在这里。 您也可以使用用户定义的触发器来处理upsert逻辑。     
您还可以添加“检查日期”值以确保它是1天的倍数:
ALTER TABLE \"statistics\" ADD CONSTRAINT \"1day_quantum\" CHECK (\"date\" = (\"date\" / 86400)::INTEGER * 86400);
如果尝试插入错误的date值,则会引发异常。 如果日期字段类型为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(秒计数),您可以将约束调整为各种量子:例如15分钟为900。     

要回复问题请先登录注册