1

我目前正在 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 查询时,它都会适当地增加列stat1stat2stat3

该脚本预计会有相当多的流量,我想弄清楚当脚本执行时如何使事情正常工作并且有几个实例同时工作。您认为哪种方法/技术最适合此类任务?

4

3 回答 3

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

无论您采取什么其他措施,您都应该这样做。

于 2011-04-22T22:51:01.420 回答
1

正如其他人所说,您需要对 user_id 和 date 对进行唯一约束。

为了在复合键 (user_id, date) 不存在时插入而不进行算术运算,并在复合键存在时使用算术更新您需要编写一些代码。非正式地,这被称为“upsert”。方法不止一种。

PosgreSQL 文档有一个使用异常处理实现这种要求的函数示例。函数的问题在于,您不能强制应用程序代码或数据库女孩每次都毫无例外地使用它。

您可以(我认为)使用suppress_redundant_updates_trigger()。触发器的优点是它们不会被应用程序代码或数据库女孩意外绕过。我自己没有使用过这种技术,所以我不能进一步评论它。此处记录了此触发器。

您还可以使用用户定义的触发器处理 upsert 逻辑

于 2011-04-23T05:30:46.890 回答
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 分钟。

于 2015-10-15T10:13:55.670 回答