【问题标题】:sqlite text as primary key vs autoincrement integerssqlite 文本作为主键与自动增量整数
【发布时间】:2021-06-27 23:00:09
【问题描述】:

我目前正在就使用 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 不是内联存储的。

我的第二种方法是使用前两个表上的 autoincrement id 作为主键,并使用表 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,类似于第二种策略的作用?

【问题讨论】:

  • 这能回答你的问题吗? Using text as a primary key in SQLite table bad?。优化如何:您可以以纯文本形式打开数据库,并看到文本 FK 是按原样存储的。
  • @astentx 那里的答案主要集中在使用文本键的性能上,我正在查看字符串是否重复,我知道性能可能会受到轻微影响,但存储更多在我的用例中很重要。

标签: sql sqlite foreign-keys primary-key


【解决方案1】:

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

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

  • 整数是固定长度的。一般来说,固定长度的键在 B 树索引中的效率略高于可变长度的键。
  • 如果字符串很短(例如 1 个或 2 个或 3 个字符),那么它们可能比整数更短(或不长)。
  • 如果您更改了字符串(例如,如果它最初拼写错误),那么使用“人工”主键可以轻松完成:只需更改一个表中的值。使用字符串本身作为键会导致对大量表进行大量更新。

【讨论】:

  • 其实Sqlite使用变长编码存储整数。见sqlite.org/fileformat2.html#record_format
  • @Shawn 。 . .这很复杂,因为内存中的表示与磁盘上的表示不同。但是我认为您在索引方面是正确的;存储将是可变长度。谢谢你的澄清。
【解决方案2】:

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

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

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

来自Rowid Tables

rowid 表(如果有的话)的 PRIMARY KEY 通常不是 表的真正主键,在某种意义上它不是唯一的 底层 B 树存储引擎使用的密钥。例外 此规则适用于 rowid 表声明 INTEGER PRIMARY KEY 时。在 例外情况下,INTEGER PRIMARY KEY 成为 rowid 的别名。

rowid 表的真正主键(用作 在底层 B 树存储引擎中查找行的关键)是 rowid.

在您的第二种方法中,实际上您并没有通过定义整数主键在 ab 的每个表中创建一个新列。
您正在做的是将现有的 rowid 列别名化:

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

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

虽然使用第一种方法可以避免在通过使用ON UPDATE CASCADE 定义外键来更新父表中的值时避免子表中的显式更新,但我建议您使用第二种方法。

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

【讨论】:

    【解决方案3】:

    为了提高性能(这也是一个很好的数据库实践),您应该坚持使用数字/整数值作为主键。

    至于第二种方法,我没有得到你所追求的概念。你能详细说明一下吗?

    【讨论】:

    • 第二种方法只是确保每个文本只存储一次,然后可以通过它的 id 来引用。所以不是insert into a values ("KeyA1")(表b相同)然后insert into c values("KeyA1", "KeyB1"),我会改为insert into a ("key_a") values ("KeyA1")(表b相同)然后insert into c values(1, 1)(假设我知道id是1之后两者),因此不重复字符串,希望它不会在数据库中重复
    猜你喜欢
    • 1970-01-01
    • 2012-01-21
    • 2013-04-18
    • 1970-01-01
    • 2014-04-21
    • 2015-12-15
    • 2016-08-08
    • 2012-07-14
    • 2012-03-13
    相关资源
    最近更新 更多