sqlite 文本作为主键与自动增量整数

sqlite text as primary key vs autoincrement integers

我目前正在考虑使用 text 列作为键的两种策略。

第一个是简单地使用 text 列本身作为键,例如:

create table a(
    key_a text primary key,
)

create table b(
    key_b text primary key,
)

create table c(
    key_a text,
    key_b text,
    
    foreign key("key_a") references a("key_a"),
    foreign key("key_b") references b("key_b")
)

我担心这会导致每个键都被复制,一次在 ab 中,另一个在 c 中,因为 text 不是内联存储。

我的第二种方法是在前两个table上使用一个autoincrement id作为主键,并在table c上使用这些id来引用对他们来说:

create table a(
    id_a integer,
    key_a text unique,
    primary key("id_a" autoincrement)
)

create table b(
    id_b integer,
    key_b text unique,
    primary key("id_a" autoincrement)
)

create table c(
    id_a integer,
    id_b integer,
    
    foreign key("id_a") references a("id_a"),
    foreign key("id_b") references b("id_b")
)

在第一种情况下,我担心文本重复是否正确?还是 sqlite 以某种方式实习这些并且只为两者使用一个 id,类似于第二种策略的作用?

为了性能(这也是一个很好的数据库实践),您应该坚持主键的 numeric/int 值。

至于第二种方法,我不明白你想要的概念。你能详细说明一下吗?

SQLite 不会自动压缩文本。所以你的问题的答案是“否”。

您应该使用文本还是自动递增的 ID 作为主键?这可能是一个复杂的问题。但令人高兴的是,答案是没有太大区别。也就是说,有一些注意事项:

  • 整数是固定长度的。一般来说,固定长度的键在 B 树索引中比可变长度的键稍微更有效。
  • 如果字符串很短(例如 1 个或 2 个或 3 个字符),那么它们可能比整数更短或更长。
  • 如果您更改字符串(例如,如果它最初拼写错误),那么使用“人工”主键可以使这变得容易:只需更改一个 table 中的值。使用字符串本身作为键可以导致对大量 tables.
  • 的大量更新

Am I right to be concerned about text duplication in the first case? Or does sqlite somehow intern these and just use an id for both, akin to what the second strategy does?

是的,你的担心是对的。文本将被复制。

此外,即使您没有在第一种方法中定义整数主键,也有一个。

来自 Rowid Tables:

The PRIMARY KEY of a rowid table (if there is one) is usually not the true primary key for the table, in the sense that it is not the unique key used by the underlying B-tree storage engine. The exception to this rule is when the rowid table declares an INTEGER PRIMARY KEY. In the exception, the INTEGER PRIMARY KEY becomes an alias for the rowid.

The true primary key for a rowid table (the value that is used as the key to look up rows in the underlying B-tree storage engine) is the rowid.

实际上,在您的第二种方法中,您并不是通过定义整数主键在 table ab 的每个中创建新列。
您正在做的是为现有的 rowid 列添加别名:

  • id_a 成为 table a
  • rowid 的别名
  • id_b 成为 table browid 的别名。

因此,就父 table 中的 space 而言,定义这些整数主键并不昂贵。

尽管使用第一种方法,当您通过使用 ON UPDATE CASCADE 定义外键更新父 table 中的值时,可以避免在子 table 中进行显式更新,你的第二种方法是我建议的。

一个由系统分配值的整数主键,您甚至不必知道或担心它是常见的做法。
您所要做的就是在您创建的查询中使用该主键及其相应的外键来访问父 tables,当您想要从它们中获取文本值时。