在 MySQL 中使用数字行 ID 有啥好处?

Posted

技术标签:

【中文标题】在 MySQL 中使用数字行 ID 有啥好处?【英文标题】:What are the merits of using numeric row IDs in MySQL?在 MySQL 中使用数字行 ID 有什么好处? 【发布时间】:2014-02-18 22:04:45 【问题描述】:

我是 SQL 新手,以关系而不是分层来考虑我的数据集对我来说是一个很大的转变。我希望能够深入了解使用数字行 ID 作为主键而不是更有意义的字符串值的性能(在存储空间和处理速度方面)与设计复杂性。

具体来说,这是我的情况。我有一个包含几百行的表(“父”),其中一列是字符串标识符(10-20 个字符),这似乎是表主键的自然选择。我有第二个表(“子表”),其中包含数十万(或可能数百万或更多)行,其中每一行都引用父表中的一行(因此我可以在子表上创建外键约束)。 (实际上,我有几个这两种类型的表,其中包含一组复杂的引用,但我认为这说明了重点。)

所以我需要子表中的一列为父表中的行提供标识符。天真地,似乎将列创建为 VARCHAR(20) 之类的东西来引用第一个表中的“自然”标识符会在存储空间和查询时间方面导致巨大的性能损失,因此我应该包括父表中的数字(可能是 auto_increment)id 列,并将其用作子表中的引用。但是,由于我加载到 mysql 的数据还没有这样的数字 id,这意味着增加了我的代码的复杂性和更多的错误机会。更糟糕的是,由于我正在进行探索性数据分析,我可能想在不对子表做任何事情的情况下处理父表中的值,所以我必须小心不要意外破坏关系删除行并丢失我的数字 id(我可能会通过将 id 存储在第三个表中或类似的东西中来解决这个问题。)

所以我的问题是,是否存在我可能不知道的优化,这意味着具有数十万或数百万行且一遍又一遍地重复仅几百个字符串值的列比最初出现的浪费更少?我不介意为了简单而牺牲效率,因为这是用于数据分析而不是生产,但我担心我会将自己编码到一个角落,我想做的所有事情都需要大量时间运行。

提前致谢。

【问题讨论】:

使用正确的索引,“性能”在很大程度上是“无关紧要的”——开销是恒定的。因此,请从非性能角度考虑问题。 Surrogate vs. natural/business keys 的可能重复项 1) 您的外键不需要在主键列上。 2) 如果你有一个一对多的关系(一个父母有很多孩子),你孩子的外键列肯定不应该是自动递增的。 3)外键约束可以有类似 RESTRICT 或 CASCADE 以避免意外错误,具体取决于您将要做什么。 @Mitch,你是对的,这似乎是重复的!我的搜索失败了。感谢您为我指明正确的方向。看到这是更有经验的数据库人员之间的公开辩论,这也有点令人欣慰。 @biogeo,这当然是一场辩论……这是 Windows VS Mac 的 DBA 版本,或者 emacs VS VI。 【参考方案1】:

我不会主要关心空间问题。一个整数键通常占用四个字节。 varchar 将占用 1 到 21 个字节,具体取决于字符串的长度。因此,如果大多数只是几个字符,varchar(20) 键将比整数键占用更多空间。但也不是特别多。

顺便说一句,两者都可以利用索引。所以访问速度并没有特别不同(当然,更长/可变长度的键会对索引性能产生边际影响)。

使用自动递增的主键有更好的理由。

    您知道最近插入了哪些值。 如果出现重复项(主键当然不应该发生这种情况),很容易确定要删除哪个。 如果您决定更改其中一个条目的“名称”,则不必更新引用它的所有表。 您不必担心前导空格、尾随空格和其他奇怪的字符。

您确实需要为额外的功能付费,在记录中增加四个字节,专门用于可能看起来没有用的东西。然而,这样的效率还为时过早,可能不值得付出努力。

【讨论】:

【参考方案2】:

戈登是对的(这不足为奇)。

在我看来,这是您不必担心的注意事项。

当您处理几十兆行或更少时,存储空间基本上是免费的。不必担心 INT 和 VARCHAR(20) 之间的区别,也不必担心添加一两列额外的磁盘空间成本。何时能以 100 美元左右的价格买到像样的 TB 级驱动器并不重要。

INT 和 VARCHARS 都可以非常有效地建立索引。您不会看到时间性能有太大差异。

这是你应该担心的。

在索引性能方面存在一个重大缺陷,您可能会遇到字符索引。您希望创建索引的列被声明为NOT NULL,并且您永远不想执行这样的查询

 WHERE colm IS NULL   /* slow! */

 WHERE colm IS NOT NULL  /* slow! */

这种事情会使索引失败。同样,如果您将函数应用于搜索列,您的性能也会受到很大影响。例如,不要这样做,因为它也破坏了索引。

 WHERE SUBSTR(colm,1,3) = 'abc'  /* slow! */

还有一个问题要问自己。您会唯一标识子表中的行吗?如果是,如何标识?他们有某种天然的复合主键吗?例如,您可以将这些列放在“子”表中。

 parent       varchar(20)   pk  fk to parent table
 birthorder   int           pk
 name         varchar(20)

然后,你可以有这样的行...

  parent      birthorder     name
  homer       1              bart
  homer       2              lisa
  homer       3              maggie

但是,如果您尝试像这样在此处插入第四行

  homer       1              badbart

您会遇到主键冲突,因为 (homer,1) 已被占用。了解如何管理子表的主键可能是个好主意。

包含数字的字符串很有趣。例如,“2”在“101”之后。您需要注意这一点。

【讨论】:

【参考方案3】:

您从数值中获得的主要好处是它们更容易“索引”。索引是 MySQL 用来更容易找到值的过程。

通常,如果您想在一个组中找到一个值,您必须遍历该组来寻找您的值。这很慢,最坏的情况是 O(n)。相反,如果您的数据采用一种很好的、​​可搜索的格式——比如binary search tree,如果可以在 O(lon n) 中找到,那么速度会更快。

索引是 MySQL 用来准备要搜索的数据的过程,它生成搜索树和其他聪明的 do-bobs,可以快速查找数据。它使许多搜索更快。但是,要做到这一点,它必须将您正在搜索的值与各种“键”值进行比较,以确定您的值是大于还是小于键。

这种比较可以在非数字值上进行。但是,比较非数字值要慢得多。如果您希望能够快速查找数据,最好的办法是使用一个整数“键”。

【讨论】:

【参考方案4】:

与基于字符串的 id 相比,数字行 ID 具有许多优势。 他们中的大多数在其他答案中都提到了。 1. 其中之一是索引。默认情况下,主键在关系数据库中建立索引。因此,拥有数字键总是更有效。 2. 数字字段的存储效率更高 2. 使用数字键连接更快。 3. row id 可以是外键。数字 id 存储紧凑,提高效率 4. 我觉得主键自增也有它的好处

-谢谢 _san

【讨论】:

以上是关于在 MySQL 中使用数字行 ID 有啥好处?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL中的zerofill有啥好处?

在 PHP 应用程序中使用 MySQL VIEWS 有啥好处? [关闭]

在 Laravel 的数据透视表中添加 id 列有啥好处?

使用一对一的表关系有啥好处? (MySQL)

除了加载行子集之外,使用 NSFetchedResultsController 有啥好处

only_full_group_by 模式有啥好处?