如果你有一张桌子:
CREATE TABLE user_widgets (
user_id int
,user_widget_name text --should probably be a foreign key to a look-up table
PRIMARY KEY (user_id, user_widget_name)
)
你可以分配user_widget_id
动态并查询:
WITH x AS (
SELECT *, row_number() OVER (PARTITION BY user_id
ORDER BY user_widget_name) AS user_widget_id
FROM user_widgets
)
SELECT *
FROM x
WHERE user_widget_id = 2;
user_widget_id
在这种情况下,按每个用户的字母顺序应用,并且没有间隙,显然,添加、更改或删除条目可能会导致更改。
更多关于手册中的窗口功能 http://www.postgresql.org/docs/current/interactive/functions-window.html.
稍微更稳定(但不完全):
CREATE TABLE user_widgets (
user_id int
,user_widget_id serial
,user_widget_name
PRIMARY KEY (user_id, user_widget_id)
)
And:
WITH x AS (
SELECT *, row_number() OVER (PARTITION BY user_id
ORDER BY user_widget_id) AS user_widget_nr
FROM user_widgets
)
SELECT *
FROM x
WHERE user_widget_nr = 2;
解决问题更新
You can实施一种制度来计算每个用户的现有小部件。但是您将很难使其对于并发写入来说无懈可击。您必须锁定整个表或使用SERIALIZABLE交易方式 http://www.postgresql.org/docs/current/interactive/transaction-iso.html#XACT-SERIALIZABLE- 两者都会真正降低性能并且需要额外的代码。
但如果你保证没有行被删除你可以采用我的第二种方法 - 一个序列user_widget_id
桌子对面,给你一个"raw"ID。序列是并发加载的一种经过验证的解决方案,保留了相对顺序user_widget_id
and is fast。您可以使用以下方式提供对表的访问view动态替换“原始”user_widget_id
与相应的user_widget_nr
就像我上面的查询一样。
您还可以(此外)“实现”无间隙user_widget_id
将其替换为user_widget_nr
在下班时间或由您选择的事件触发。
为了提高性能,我将有以下顺序user_widget_id
从一个非常高的数字开始。似乎每个用户只能有几个小部件。
SELECT setval(user_widgets_user_widget_id_seq', 100000);
如果没有足够高的数字来保证安全,请添加一个标志。使用条件WHERE user_widget_id > 100000
快速识别“原始”ID。如果您的桌子很大,您可能需要添加一个部分索引 http://www.postgresql.org/docs/current/interactive/indexes-partial.html使用条件(该条件会很小)。用于上述视图中CASE
陈述。在这个“具体化”ID 的语句中:
UPDATE user_widgets w
SET user_widget_id = u.user_widget_nr
FROM (
SELECT user_id, user_widget_id
,row_number() OVER (PARTITION BY user_id
ORDER BY user_widget_id) AS user_widget_nr
FROM user_widgets
WHERE user_widget_id > 100000
) u
WHERE w.user_id = u.user_id
AND w.user_widget_id = u.user_widget_id;
可能会跟进REINDEX
甚至VACUUM FULL ANALYZE user_widgets
下班时间。考虑一个FILLFACTOR http://www.postgresql.org/docs/current/interactive/sql-createtable.html#SQL-CREATETABLE-STORAGE-PARAMETERS低于 100,因为列将至少更新一次。
我当然会not将其留给应用程序。这会带来多个额外的故障点。