PostgreSQL 递增表中行的值
我目前正在 PHP 构建一个脚本,该脚本必须在完成其目的时更新统计信息。该脚本通过网络浏览器访问,并且根据流量,它可能会同时执行。我必须保证统计数据是正确的。
为了给您提供图片,假设我们有一个表:
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 列。
该脚本预计会有相当多的流量,我想弄清楚当脚本执行并且有几个实例同时工作时如何使事情正常工作。您认为哪种方法/技术最适合此类任务?
I'm currently PHP building a script that has to update statistics when it finishes it's purpose. The script is accessed by web browser and depending on the traffic it may be executed simultaneously. I have to guarantee the statistics are right.
To give you the picture let's say we have a table:
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);
Every day a new row is inserted in the table so we could have a daily, weekly, monthly, yearly statistics. I have to be sure only one row is inserted per user_id per day. Also whenever an UPDATE query is executed it would increment the columns stat1,stat2,stat3 appropriately.
This script is expected to have quite some traffic and I want to figure out how to make things work when the script is executed and has a couple of instances working simultaneously. What method/technique do you find best for such tasks ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
最简单的解决方案是添加唯一约束,
无论您采取什么其他措施,您都应该这样做。
The simplest solution is to add a unique constraint
You should definitely do this regardless of what other measures you take.
正如其他人所说,您需要对 user_id 和 date 对进行唯一约束。
为了在复合键(user_id、date)不存在时不进行算术插入,并在复合键存在存在时进行算术更新,您需要编写一些代码。非正式地,这称为“更新插入”。有不止一种方法。
PosgreSQL 文档有一个使用异常处理实现此类需求的函数示例。函数的问题在于你不能强迫应用程序代码或数据库女孩每次都无一例外地使用它。
您可以(我认为)使用 suppress_redundant_updates_trigger()< /a>.触发器的优点是它们不会被应用程序代码或数据库管理员意外绕过。我自己没有使用过这种技术,所以我无法进一步评论。此触发器记录在此处。
您还可以使用用户定义的触发器处理更新插入逻辑< /a>.
You need a unique constraint on the pair user_id and date, as others have said.
In order to insert without doing arithmetic when the compound key (user_id, date) doesn't exist, and to update with arithmetic when the compound key does exist, you need to write some code. Informally, this is called an "upsert". There's more than one way.
PosgreSQL docs have an example of a function that implements this kind of requirement using exception handling. The problem with a function is that you can't force application code or database girls to use it every time without exception.
You can (I think) use the suppress_redundant_updates_trigger(). The advantage of triggers is that they can't be bypassed accidentally by application code or by database girls. I have not used this technique myself, so I can't comment further on it. This trigger is documented here.
You can also handle the upsert logic with a user-defined trigger.
您还可以为日期值添加 CHECK 以确保它是 1 天的倍数:
如果尝试插入错误的日期值,则会抛出异常。
如果日期字段类型为 TIMESTAMP 或 TIMESTAMPTZ,则 CHECK 会更复杂:
通过更改 86400(秒数),您可以将约束调整为各种量程:例如 900 为 15 分钟。
Also you can add CHECK for date value to ensure that it a multiple of 1 day:
Then exception will be thrown if one try insert wrong value of date.
If date field type will be TIMESTAMP or TIMESTAMPTZ then CHECK is more complicated:
By changing 86400 (seconds count) you can adjust constraint to various quantum: 900 for 15 mins for example.