【问题标题】:In what cases should the AUTOINCREMENT be used instead of the default ROW ID?在什么情况下应该使用 AUTOINCREMENT 而不是默认的 ROW ID?
【发布时间】:2017-02-10 18:05:37
【问题描述】:

在Sqlite中,有两种方法可以创建由数据库引擎生成的单调递增的主键值,通过默认的ROWID机制或者通过AUTOINCREMENT机制。

sqlite> -- Through the default ROWID mechanism
sqlite> CREATE TABLE foo(id INTEGER NOT NULL PRIMARY KEY, foo);
sqlite> INSERT INTO foo (foo) VALUES ('foo');
sqlite> INSERT INTO foo (foo) VALUES ('bar');
sqlite> SELECT * FROM foo;
1|foo
2|bar
sqlite>
sqlite> -- Through the AUTOINCREMENT mechanism
sqlite> CREATE TABLE bar(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, bar);
sqlite> INSERT INTO bar (bar) VALUES ('foo');
sqlite> INSERT INTO bar (bar) VALUES ('bar');
sqlite> SELECT * FROM bar;
1|foo
2|bar
sqlite> -- Only the AUTOINCREMENT mechanism uses the sqlite_sequence table
sqlite> SELECT * FROM sqlite_sequence WHERE name in ('foo', 'bar');
bar|2

documentation 似乎暗示使用AUTOINCREMENT 不好:

AUTOINCREMENT 关键字会带来额外的 CPU、内存、磁盘空间和磁盘 I/O 开销,如果不是严格需要,应避免使用。通常不需要。

如果 AUTOINCREMENT 关键字出现在 INTEGER PRIMARY KEY 之后,则会更改自动 ROWID 分配算法,以防止在数据库的生命周期内重复使用 ROWID。换句话说,AUTOINCREMENT 的目的是防止重复使用以前删除的行中的 ROWID。

[使用 AUTOINCREMENT,] SQLite 使用名为“sqlite_sequence”的内部表来跟踪表所拥有的最大 ROWID。每当创建包含 AUTOINCREMENT 列的普通表时,就会自动创建和初始化 sqlite_sequence 表。 sqlite_sequence 表的内容可以使用普通的 UPDATE、INSERT 和 DELETE 语句进行修改。但是对这个表进行修改可能会扰乱 AUTOINCREMENT 密钥生成算法。在进行此类更改之前,请确保您知道自己在做什么。


在什么情况下适合使用 AUTOINCREMENT 关键字?

【问题讨论】:

    标签: sqlite


    【解决方案1】:

    文档说

    AUTOINCREMENT 的目的是防止重复使用以前删除的行中的 ROWID。

    因此,当您需要防止重复使用以前删除的行中的 ROWID 时,使用 AUTOINCREMENT 关键字是合适的。如果您对这些已删除的行有外部引用,则可能需要这样做,并且不得将它们与新行混淆。

    【讨论】:

    • 假设您启用了外键,则不可能对已删除的行进行外部引用。假设您禁用了外键,您是否有一个用例说明何时保留对已删除行的外部引用是个好主意?
    • 这里,“外部”是指在数据库之外。
    • 对不起,我还是不明白 :)。外部数据库何时保留对已删除 id 的引用有用?
    • 一些同步机制,可以记住最后同步的行。或者印在一张纸上。
    • @MatthewMoisen 另一个很好的例子是 URL。如果你删除一个页面,我通过书签访问它,我宁愿得到一个 404/410 错误,而不是一个完全不相关的页面,因为你重用了 ID。由于我的书签不在您的数据库中,因此您无法通过外键确保完整性。
    【解决方案2】:

    "AUTOINCREMENT 的目的是防止 ROWID 的重用 以前删除的行。”

    断章取意,这听起来像是唯一的目的。我认为 AUTOINCREMENT 最明显的决策点之一是您是否需要单调递增整数的保证。反过来,这种需求肯定是最常见的,因为您需要知道插入发生的顺序。人们可能更喜欢整数而不是时间戳,因为:时钟分辨率不足,担心时钟不稳定,如果涉及多个时钟源则难以同步等。

    当然,我们总是可以构造一个事务首先完成但获得的数字高于竞争事务的情况。然而,这些似乎几乎对应于两个人可能不同意首先“发生”的交易的情况,所以单调性的保证是好的,IMO。如果您使用 AUTOINCREMENT,这是 SQLite 提供的保证。

    “你有没有一个用例说明什么时候保持一个外部的 引用已删除的行?”

    与其说是不是一个好主意,倒不如说是:如果人们看到/使用任何形式的 ID,如果他们认为唯一的数字被重新分配,就会造成混乱。这是in the wild 的示例。这是单调递增 ID 需求范围的一个子集,但比您想象的更常见。人类善于下意识地吸收数字“应该”总是变大的事实。例如,在 ye olde slashdot 时代,人们可以通过查看您的用户 ID 号来判断您成为会员的时间。在 slashdot 上,我猜快速将鼠标悬停在用户名上可以完成同样的事情,并且不必去查看他们的个人资料。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      相关资源
      最近更新 更多