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。
让我们开始:
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。