我应该索引一个经常更新的外键吗

Posted

技术标签:

【中文标题】我应该索引一个经常更新的外键吗【英文标题】:Should I index a foreign key that is going to be updated often 【发布时间】:2017-10-21 09:55:50 【问题描述】:

我正在尝试创建一个图书馆关系数据库,其中有两个表:用户和书籍。这种关系是一对多:一。一个用户有很多书,而一本书只有一个用户拥有。我在想 book 表应该有一个引用用户 id 的外键列。

但是,如果我想获取给定用户的所有书籍,我遇到了问题。 唯一的选择是使用 join 查询用户 ID 等于给定用户 ID 的书籍。 但是如果有很多书,那将需要很多时间。 所以有人可能会建议将外键列索引为非聚集索引。但是,图书用户组合会经常更新——您在此图书馆中的图书存放时间不会超过一天。但我读到更新索引列通常不是最佳做法。

那我该怎么办?这种情况的最佳解决方案是什么?

【问题讨论】:

***.com/help/how-to-ask Should I make a foreign key that can be null or make a new table?的可能重复 不重复。我的主要问题是我是否应该索引经常更新的列,如果不是,那么正确的解决方案是什么 你的主要问题是它是一个糟糕的设计。建议您阅读链接和其他类似的内容。 通常有一个用于书籍的表,一个用于用户,一个用于 user_has_borrowed_book。您可以改为使用 NULL 存储用户表和组合其他两者的表。出于什么原因更喜欢哪个是设计质量的问题。 (包括实施问题。)第一个设计很简单,第二个不是。查找并关注有关信息建模和数据库设计的文本。当我们可以证明它有性能问题而另一个没有时,我们会放弃一个简单的设计。您需要对前者有更多的经验,然后才能欣赏后者。 【参考方案1】:

双向查询的最佳性能应该包括一个中间表来存储关系。客户和图书都应具有唯一索引 中间表 - borrowing_table user_idbook_id 列 您将用户和图书索引(id)的信息存储在此表上,因此您可以通过 user_id 查询该表并获取哪个此人已借书,也可以通过books_id查询快速获取用户。

【讨论】:

首先,可以简化:关系是一对多而不是多对多——一本书只能由一个用户拥有。您的解决方案解决了查询用户拥有的书籍列表的性能。但另一个查询是更新书的所有者,考虑到性能,这在您的解决方案中没有正确解决 用户换书或用户还书时书表不需要更新 但是如果用户想借一本书,我需要查询这本书是否已经借阅了【参考方案2】:

您应该在book_id 上有一个索引。

您对“频繁”更新的担忧不适用于库设置。图书馆在几天和几周的时间框架内工作。数据库在毫秒、秒和分钟的时间范围内工作。从数据库的角度来看,图书馆中看似常见的东西却相当罕见。

也就是说,我建议使用中间表,而不是因为您在任何给定时间点都有 1-n 关系。相反,你有一个时间平铺的关系。所以:

create table UserBooks (
    UserBookId int,  -- serial, auto_increment, identity, generated always
    UserId int references Users(UserId),
    BookId int references Books(BookId),
    FromDate datetime,
    ToDate datetime,
    DueDate datetime,
    OverdueFees numeric(20, 4)
    . . .
);

换句话说,“借”应该是实体本身,因为除了书籍和用户之外,还有更多的信息。

【讨论】:

我理解你所说的频率,但每周更新索引并不需要在短时间内重建一次索引(我读到这不是一件好事)

以上是关于我应该索引一个经常更新的外键吗的主要内容,如果未能解决你的问题,请参考以下文章

我应该使用外键吗? [复制]

我需要在 Oracle 的外键上创建索引吗?

mysql中的外键是什么?以及需要使用外键吗?

我可以在我的大多数表中使用我的外键作为我的主键吗?

Oracle一个字段的的外键可以当另一个字段的主键吗

Eloquent 可以替换数据库中的外键吗?