【问题标题】:Postgresql - `serial` column & inheritence (sequence sharing policy)Postgresql - `serial` 列和继承(序列共享策略)
【发布时间】:2016-05-16 10:34:04
【问题描述】:

在postgresql中,当从父表继承serial列时,该序列由父子表共享。

是否可以继承 serial 列,同时让 2 个表具有单独的序列值,例如两个表的列都可以具有值 1

这是否可行且合理,如果可以,该怎么做?


@更新

我想避免序列共享的原因是:

    1. 多个表共享单个 int 范围可能会用完 MAX_INT,使用 bigint 可以改善这一点,但需要更多空间 也是。
    1. 当多个表同时插入时存在一种资源锁定,所以我猜这是一个性能问题。
    1. id 从 1 跳到 5,然后可能跳到 1000,看起来并不那么漂亮。

@摘要

解决方案

  • 如果希望子表有自己的顺序,但仍然保持父子表之间的全局顺序。 (@wildplasser 的回答中所述。

    然后可以为每个子表添加一个sub_id serial 列。

  • 如果希望子表有自己的顺序,而父子表之间不需要全局顺序,

    有两种方式:

    1. 使用int 代替serial。 (@lsilva 的回答中所述。

      步骤:

      • 在父表中定义类型为int或bigint,
      • 为每个父子表创建一个单独的序列,
      • 使用各自序列的 nextval 为每个表指定 int 类型的默认值, 重新创建表时不要忘记维护/重置序列,
    2. 直接在子表中定义id serial,而不是在父表中。

【问题讨论】:

  • 向子表添加another序列列?
  • @wildplasser 您的意思是子表中有 2 个串行列吗?这肯定行得通,但我正在寻找更好的解决方案。
  • 是的,当然。在大多数情况下它没有意义,但在这种情况下它可以。并且没有更好的解决方案(除了省略它并在(父序列)子表中使用像 row_number() 这样的枚举)
  • 请记住一个经常被误解的事实,即序列并不能确保 ID 的无间隙进展(因为它们如何与事务和类似的种族交互),也不能保证列值的唯一性。因此,添加额外的序列并不能保证您不会在表 A 中获得 ID 1、3、5 和在表 B 中获得 2、4、6;并且保持相同的顺序不会阻止您手动将 ID 1 插入所有表中。因此,可能值得确认为什么您要这样做,以及您希望分离的序列具有哪些属性。
  • @IMSoP 我更新了问题以添加我想要的原因。

标签: postgresql inheritance


【解决方案1】:
DROP schema tmp CASCADE;
CREATE schema tmp;
set search_path = tmp, pg_catalog;

CREATE TABLE common
        ( seq SERIAL NOT NULL PRIMARY KEY
        );

CREATE TABLE one
        ( subseq SERIAL NOT NULL
        , payload integer NOT NULL
        )
        INHERITS (tmp.common)
        ;

CREATE TABLE two
        ( subseq SERIAL NOT NULL
        , payload integer NOT NULL
        )
        INHERITS (tmp.common)
        ;

/**
\d common
\d one
\d two
\q
***/

INSERT INTO one(payload)
SELECT gs FROM generate_series(1,5) gs
        ;

INSERT INTO two(payload)
SELECT gs FROM generate_series(101,105) gs
        ;

SELECT * FROM common;
SELECT * FROM one;
SELECT * FROM two;

结果:

NOTICE:  drop cascades to table tmp.common
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
CREATE TABLE
CREATE TABLE
INSERT 0 5
INSERT 0 5
 seq 
-----
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
(10 rows)

 seq | subseq | payload 
-----+--------+---------
   1 |      1 |       1
   2 |      2 |       2
   3 |      3 |       3
   4 |      4 |       4
   5 |      5 |       5
(5 rows)

 seq | subseq | payload 
-----+--------+---------
   6 |      1 |     101
   7 |      2 |     102
   8 |      3 |     103
   9 |      4 |     104
  10 |      5 |     105
(5 rows)

但是:实际上你不需要 subseq 列,因为你总是可以通过 row_number() 枚举它们:

CREATE VIEW vw_one AS
SELECT seq
        , row_number() OVER (ORDER BY seq) as subseq
        , payload
FROM one;

CREATE VIEW vw_two AS
SELECT seq
        , row_number() OVER (ORDER BY seq) as subseq
        , payload
FROM two;

[结果相同]


而且,您可以向子表添加 UNIQUE AND PRIMARY KEY 约束,例如:

CREATE TABLE one
        ( subseq SERIAL NOT NULL UNIQUE
        , payload integer NOT NULL
        )
        INHERITS (tmp.common)
        ;    
ALTER TABLE one ADD PRIMARY KEY (seq);

[表二类似]

【讨论】:

  • 好的,这可能是一个解决方案。我会接受它,除非出现另一个更好的解决方案。我想知道postgresql是否有可能在继承时提供关于序列共享的选项。
  • 在父表和所有子表中不需要全局 id 的情况下,@Isilva 的解决方案似乎也很有效。
  • 使用窗口函数row_number() 我猜有一些开销。
  • 存储冗余数据也有一些开销。
【解决方案2】:

我用这个:

Parent table definition:

CREATE TABLE parent_table (
  id bigint NOT NULL,


Child table definition:


CREATE TABLE cild_schema.child_table
(
  id bigint NOT NULL DEFAULT nextval('child_schema.child_table_id_seq'::regclass),

我通过使用序列号作为默认值来模拟序列号。

【讨论】:

  • 您可以在父表中添加不同的默认值,或者在另一个子表中使用不同的序列
  • 您的意思是不要使用serial类型,而是使用intbigint,并手动为每个父子表单独创建一个序列,并为@指定默认值987654325@ 或 bigint 为每个表使用它们自己的序列的nextval 类型?这似乎更简单。
  • 请注意,如果您使用CREATE SEQUENCE ... OWNED BY,整数列与SERIAL 列或多或少无法区分,而SERIAL 列实际上并不是它自己的数据类型。
  • 是的,这正是我的意思 Eric :)。如果对您有用,请接受答案。
  • 不编译。你测试了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多