【问题标题】:Foreign keys vs Composite keys in MySQLMySQL中的外键与复合键
【发布时间】:2020-06-16 08:39:35
【问题描述】:

我有一张这样的桌子:

USER_RELATIONSHIP
----------------------
user_id     follows_id
1           2
1           3
2           1
3           1

user_id 和 follow_id 都是指向 User 表的外键。 USER_RELATIONSHIP 表非常大,我经常检查是否存在用户关系(例如,用户 A 跟随用户 B)。

鉴于这些外键已编入索引,SQL 是否能够在 O(1) 中找到关系(给定 user_id 和 follow_id)?

如果不是,将上面的两个字段压缩为一个索引复合键,该键对 user_id 和 follow_id 进行哈希处理,并具有这样的 USER_RELATIONSHIP 表,是否更高效?

USER_RELATIONSHIP
----------------------
composite_key
298437920           
219873423           
918204329          
902348293           

【问题讨论】:

  • @nbk 您的评论与我的问题无关。
  • 散列索引有一些限制,尤其是它们变大的速度非常快也见dev.mysql.com/doc/refman/5.6/en/index-btree-hash.html,我的观点是唯一的约束
  • 如果您担心 FK 对性能的影响,请摆脱它们(但保留关联的 INDEX)。在大多数情况下,您的应用程序“做正确的事”,从而消除了对 FK 的需求。 (是的,是的,FK 是用来抓捕“做错事”的流氓临时 DML。)

标签: mysql sql


【解决方案1】:

将作为哈希函数结果的字符串存储到索引中不会使其成为哈希索引。

它仍然是一个 B-tree 索引,查找需要 O(log n) 时间。

在 MySQL 中,常见的存储引擎 InnoDB(默认)和 MyISAM 不支持哈希索引。只有 Memory 和 NDB 存储引擎支持哈希类型索引。

https://dev.mysql.com/doc/refman/8.0/en/create-index.html:

在 InnoDB 中无法进行 O(1) 查找。

在散列函数的字符串结果上使用多列索引与使用索引在复杂性方面没有区别。

【讨论】:

  • 我觉得这个问题听起来很熟悉……我在 2011 年回答过一个这样的问题! stackoverflow.com/a/7681319/20860 今天的问题我不会以重复的形式结束,因为 9 年后问同样的问题并非没有道理,以防万一最近版本的 MySQL 有新的索引功能。但在这种情况下,旧的答案也适用于当前的 MySQL。
  • 感谢您的意见。您是否建议我将 USER_RELATIONSHIP 与两个索引 FK 保持原样?
  • 是的,通过user_idfollows_id 查找条目集将变得更加容易。如果对它们进行哈希处理,您将只能查找特定的对,而不是集合。
【解决方案2】:

将数据压缩到单个列中并没有提高性能。我很好奇你为什么要问。

如果您在(user_id, follows_id) 上有一个复合索引,则查找时间为 O(log n) - 表中行数的日志。对于大多数桌子来说,这非常小。而且,如果表大到可以测量索引查找时间,那么您就更需要索引了。

【讨论】:

  • 因为哈希表在 O(1) 时间执行读取。 O(1) 总是优于 O(log n)。如果我使用唯一散列索引的复合键,我不会达到 O(1) 吗?另外,如果一行包含两个外键,如 USER_RELATIONSHIP 表,是否会自动创建复合索引?
  • @Rage 。 . .假设哈希表适合内存。另外,big-oh 符号只是说明当 n --> 无穷大时会发生什么。对于较小的 n 值——数百万和数十亿可能很小——其他常数可能更重要。所以,这取决于。这甚至没有考虑到最常见的存储引擎不支持哈希索引。
  • 同意。您是否建议保留我的 USER_RELATIONSHIP 表?
  • @Rage 。 . .如果您关心使用两个键查找行的性能,那么创建一个复合 b-tree 索引或复合主键。
  • 现在使用两个索引外键与创建索引复合主键相比,表的时间复杂度差异是多少?
猜你喜欢
  • 1970-01-01
  • 2016-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
相关资源
最近更新 更多