【问题标题】:Does PRIMARY KEY constraint defined on table level guarantees AUTOINCREMENT and no values reuse?在表级别定义的 PRIMARY KEY 约束是否保证 AUTOINCREMENT 并且没有值重用?
【发布时间】:2019-08-19 06:39:33
【问题描述】:

考虑下面的表定义:

CREATE TABLE names (
    id INTEGER,
    name TEXT NOT NULL,
    PRIMARY KEY (id)
)

它是否保证id 将在每次新插入时自动递增,并且已删除行的值不会被重用?

我查阅了 Sqlite3 的文档,但找不到答案。

【问题讨论】:

  • 在表中最大的rowid确实是一个非常大的数字后(或者如果表中最大的一个被删除),可以重用丢失的rowid,除非AUTOINCREMENT用于更改新的rowid计算rowid。详情请见sqlite.org/autoinc.html
  • 是的,我已经阅读了该文档,但它没有回答我的问题。

标签: sqlite


【解决方案1】:

id INTEGER PRIMARY KEY 自己保证(要求)一个唯一的整数值,如果没有专门分配值,将提供一个,直到最高值达到 64 位有符号整数 (9223372036854775807) 的最高允许值,之后未使用可以找到并应用价值。

使用AUTOINCREMENT 可以保证(如果未规避)始终提供更高的值,但如果达到 9223372036854775807 而不是分配未使用的数字,则会导致 SQLITE_FULL 错误。从分配的数字来看,这是唯一的区别。

都不保证单调递增的值。

没有 AUTOINCREMENT 的计算/算法等价于

  • 1 + max(rowid),如果该值大于 9223372036854775807,则会尝试查找未使用的值,因此较低。

    • 我没有看到有人遇到过没有分配随机未使用值的情况。

使用 AUTOINCREMENT 计算/算法是

  • 大于 1 + max(rowid) 或 SELECT seq FROM sqlite_sequence WHERE name = 'the_table_name_the_rowid_is_being_assigned_to' 如果值大于 9223372036854775807 则 SQLITE_FULL ERROR。

  • 请注意,无论哪种方式,最大 rowid 都有可能用于最终不会插入的行,因此可能存在间隙。

最好的答案可能是:最好/建议仅将 id 列用于其预期目的,即有效识别行而不是作为处理其他数据要求的手段,如果这样做,就不需要 AUTOINCREMENT (有overheads

总之

是否保证id会自动递增

已删除行的值不会被重复使用?

NO对于给定的代码

对于:-

CREATE TABLE names (id INTEGER PRIMARY KEY AUTOINCREMENT name TEXT NOT NULL)

再次NO,如果达到 9223372036854775807 则会导致 SQLITE_FULL 错误,否则 YES


所以真正的 AUTOINCREMENT 只有在插入第 9223372036854775807 行时才真正相关(如果 id 按预期/预期使用)。

也许考虑以下几点:-

DROP TABLE IF EXISTS table1;
DROP TABLE IF EXISTS table2;

CREATE TABLE IF NOT EXISTS table1 (id INTEGER PRIMARY KEY, somecolumn TEXT);
CREATE TABLE IF NOT EXISTS table2 (id INTEGER PRIMARY KEY AUTOINCREMENT, somecolumn TEXT);

INSERT INTO table1 VALUES (9223372036854775807,'blah'); 
INSERT INTO table2 VALUES (9223372036854775807,'blah');
INSERT INTO table1 (somecolumn) VALUES(1),(2),(3); 
SELECT * FROM table1;
INSERT INTO table2 (somecolumn) VALUES(1),(2),(3);

这将创建两个相似的表,唯一的区别是使用 AUTOINCREMENT。每个都插入了 id 列允许的最高值的行。

然后尝试插入 3 行,其中 id 将由 SQLite 分配。

在没有 AUTOINCREMENT 的情况下将 3 行插入到表中,但在使用 AUTOINCREMENT 时不插入任何行。根据:-

CREATE TABLE IF NOT EXISTS table1 (id INTEGER PRIMARY KEY, somecolumn TEXT)
> OK
> Time: 0.098s


CREATE TABLE IF NOT EXISTS table2 (id INTEGER PRIMARY KEY AUTOINCREMENT, somecolumn TEXT)
> OK
> Time: 0.098s


INSERT INTO table1 VALUES (9223372036854775807,'blah')
> Affected rows: 1
> Time: 0.094s


INSERT INTO table2 VALUES (9223372036854775807,'blah')
> Affected rows: 1
> Time: 0.09s


INSERT INTO table1 (somecolumn) VALUES(1),(2),(3)
> Affected rows: 3
> Time: 0.087s


SELECT * FROM table1
> OK
> Time: 0s


INSERT INTO table2 (somecolumn) VALUES(1),(2),(3)
> database or disk is full
> Time: 0s

table1 的 SELECT 的结果(由于随机性可能会有所不同)是:-

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 2021-07-26
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多