如何创建 PostgreSQL 分区序列?
是否有一种简单(即非 hacky)且无竞争条件的方法在 PostgreSQL 中创建分区序列。示例:
在问题中使用正常序列:
| Project_ID | Issue |
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
在问题中使用分区序列:
| Project_ID | Issue |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
Is there a simple (ie. non-hacky) and race-condition free way to create a partitioned sequence in PostgreSQL. Example:
Using a normal sequence in Issue:
| Project_ID | Issue |
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
Using a partitioned sequence in Issue:
| Project_ID | Issue |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不相信有一种像常规序列一样简单的简单方法,因为:
nextval('myseq')
;但它无法引用其他列来通知函数该值应来自哪个流。你可以做出一些有用的东西,但你可能不会认为它很简单。依次解决上述问题:
multiseq(partition_id, next_val)
。编写一个
multinextval(seq_table,partition_id)
函数,执行如下操作:seq_table
中提到的表。partition_id
的行。 (或者如果没有现有行,则插入值为 2 的新行。)在您的项目表上创建一个插入触发器,使用调用
multinextval('projects_table', NEW.Project_ID)
进行插入。我自己没有使用整个计划,但我单独尝试了与每个步骤类似的方法。如果您想尝试此操作,可以提供
multinextval
函数和触发器的示例...I do not believe there is a simple way that is as easy as regular sequences, because:
nextval('myseq')
; but it cannot refer to other columns to inform the function which stream the value should come from.You can make something that works, but you probably won't think it simple. Addressing the above problems in turn:
multiseq (partition_id, next_val)
.Write a
multinextval(seq_table, partition_id)
function that does something like the following:seq_table
.partition_id
, with an incremented value. (Or insert a new row with value 2 if there is no existing one.)Create an insert trigger on your projects table that uses a call to
multinextval('projects_table', NEW.Project_ID)
for insertions.I have not used this entire plan myself, but I have tried something similar to each step individually. Examples of the
multinextval
function and the trigger can be provided if you want to attempt this...我有同样的需求,我的解决方案几乎就是@Edmund 上面所说的。
到目前为止我发现的唯一缺点是,由于我的查询查找序列列的 MAX() 值,理论上,如果删除最新行 (= by这样做可以减少最大记录序列号)并添加一个新序列号。
在未来的迭代中,我可能会创建一个专门用于存储每个单独序列的最大值的表,但我想对其在重负载下如何工作进行一些性能测试。我有效地替换了原生序列,而没有对其进行所有优化,这肯定会带来缺点。
就我而言,我在具有不同分区列的许多列上使用序列号,因此我创建了一个从触发器调用的通用函数。
这是函数。您需要
hstore
扩展来运行它。这是每列的触发器(用实际名称替换方括号中的内容):
顺便说一句,我已将其自动化。我对每个序列列使用列注释,例如
nssequence:partition_column_name
。我还编写了一个脚本,用于查找具有此类评论的所有列并向它们添加触发器。这是查找所有序列列的查询:
最后,我还有一个清理机制,用于查找在不再存在或不再说它们是序列号的列上创建的触发器,但这可能对此来说太详细了回答。
I had the same need and my solution was pretty much what @Edmund said above.
The only downside I found so far is that since my query looks for the MAX() value of the sequence column, in theory, the number could be re-used if you delete the latest row (= by doing that you decrement the max recorded sequence number) and add a new one.
In some future iteration I will probably create a table dedicated to storing max values of each separate sequence, but I want to do some performance testing on how would that work under a heavy load. I'm effectively replacing native sequences without all their optimisations, which must come with downsides.
In my case, I am using the sequence numbers over a lot of columns with different partition columns, so I created a universal function I call from my triggers.
Here is the function. You'll need
hstore
extension to run it.and here is the trigger for each column (replace things in square brackets with actual names):
Just by the way, I have automated this. I use a column comment on each sequence column, such as
nssequence:partition_column_name
. I also wrote a script that looks for all columns that have the such comment and adds the triggers to them.This is the query to find all sequence columns:
Finally I also have a cleanup mechanism in place that looks for triggers that are created over columns that no longer exist or no longer say they are a sequence number, but that's probably too much detail for this answer.