postgresql SERIAL 是否保证单个插入语句中没有间隙?

Is postgresl SERIAL guaranteeing no gaps within single insert statement?

让我们开始:

CREATE TABLE "houses" (
  "id" serial NOT NULL PRIMARY KEY, 
  "name" character varying NOT NULL)

假设我尝试在单个语句中同时 (!) 插入 table 多条记录(可能 10 条或 1000 条)。

INSERT INTO houses (name) VALUES
    ('B6717'),
    ('HG120');

是否保证当单个线程在单个语句中插入 X 条记录时(当同时其他线程同时尝试将其他记录插入到相同的table)时,这些记录将具有 ID 编号从 A 到 A+X-1 ?或者是否有可能 A+100 被线程 1 占用,A+99 被线程 2 占用?

使用两个 PgAdmin 连接一次插入 10000 条记录似乎足以证明串行类型不能保证在我的 PostgreSQL 9.5 上的批处理中的连续性

DO
$do$
BEGIN 
FOR i IN 1..200 LOOP
  EXECUTE format('INSERT INTO houses (name) VALUES %s%s;', repeat('(''a' || i || '''),', 9999), '(''a' || i || ''')');  
END LOOP;
END
$do$;

以上导致属于两个不同批次的 ID 之间非常频繁的重叠

SELECT * FROM houses WHERE id BETWEEN 34370435 AND 34370535 ORDER BY id;

34370435;"b29"
34370436;"b29"
34370437;"b29"
34370438;"a100"
34370439;"b29"
34370440;"b29"
34370441;"a100"
...

我原以为这会更难证明,但事实证明这并不能保证。

我使用了一个ruby脚本让4个线程同时插入了数千条记录,并检查了由单个语句创建的记录是否有间隙,它们确实存在。

  Thread.new do
    100.times do |u|
      House.import(1000.times.map do |i|
        {
          tenant: "#{t}-#{u}",
          name: i,
        }
      end)
    end
  end
end.each(&:join)

House.distinct.pluck(:tenant).all? do |t|
  recs = House.where(
    tenant: t,
  ).order('id').to_a
  recs.first.id - recs.first.name.to_i == recs.last.id - recs.last.name.to_i
end

差距示例:

[#<House:0x00007fd2341b5e00
  id: 177002,
  tenant: "0-43",
  name: "0",>,
 #<House:0x00007fd2341b5c48
  id: 177007,
  tenant: "0-43",
  name: "1">,
  ...

如您所见,在同一个 INSERT 语句中插入的第一行和第二行之间的 GAP 为 5。