【问题标题】:How to properly index a many-many association table?如何正确索引多对多关联表?
【发布时间】:2011-06-10 12:28:24
【问题描述】:

在这样的典型多对多排列中......

电影演员 Movies_Actors ------ ------ ------------- movie_ID actor_ID FK_movie_ID 标题名称 FK_actor_ID

...应如何为关联表 ('Movies_Actors') 建立索引以获得最佳读取速度?

我通常只使用关联表中的复合主键来完成此操作,如下所示:

CREATE TABLE Movies_Actors (
  FK_movie_ID INTEGER,
  FK_actor_ID INTEGER,
  PRIMARY KEY (FK_movie_ID, FK_actor_ID)
)

但是,这似乎索引仅在搜索 both movie_IDactor_ID 时才有用(尽管我不确定复合索引是否也适用于各个列)。

由于“电影 X 中有哪些演员”和“演员 Y 出演了哪些电影”都是该表的常见查询,因此似乎每列都应该有一个单独的索引来快速定位演员和电影他们自己。复合索引是否有效地做到了这一点?如果没有,那么在此表上使用复合索引似乎毫无意义。如果复合索引没有意义,那么主键该怎么办?候选键显然是两列的组合,但如果生成的组合索引毫无意义(它一定不是?),这似乎是一种浪费。

此外,this link 增加了一些混淆,并表明实际上指定 两个 复合索引甚至可能有用...其中一个为 (FK_movie_ID, FK_actor_ID),另一个相反为 @ 987654328@,可以选择哪个是主键(因此通常是聚集的),哪个“只是”一个唯一的复合索引,基于哪个方向被查询更多。

真实的故事是什么?复合索引是否会自动有效地索引每一列以在其中一个或另一个上进行搜索?最佳(读取速度,而不是大小)关联表是否应该在每个方向上都有一个复合索引并且在每一列上都有一个?幕后机制是什么?


编辑:我发现了这个相关的问题,由于某种原因我在发布之前没有找到...... How to properly index a linking table for many-to-many connection in MySQL?

【问题讨论】:

  • 非常有趣的问题,相信很多人都错了。

标签: sql sql-server postgresql many-to-many query-optimization


【解决方案1】:

(虽然我不确定是否 综合指数也适用于 个别列)。

是的,可以。但只有前缀:http://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys

此外,此链接增加了一些混乱 并表明它甚至可能是 实际指定两个有用 综合指数...其中之一为 (FK_movie_ID、FK_actor_ID)和 其他反向为(FK_actor_ID, FK_movie_ID),

这就是真正要做的事情。

将一个作为聚簇索引,另一个作为非聚簇索引,无论如何都将包含聚簇索引键 - 因此无需再次包含该列(感谢 JNK)。

CREATE CLUSTERED INDEX a on Movies_Actors (fk_movie_id, fk_actor_id);
CREATE NONCLUSTERED INDEX b on Movies_Actors (fk_actor_id);

真实的故事是什么?

http://Use-The-Index-Luke.com/ :)

自动生成复合索引 有效地索引每一列 搜索一个或另一个?

没有。只有索引的前缀。如果您有索引 (a,b,c),则查询 a=?和 b =?可以使用索引。然而 c=?不能,也不能 b=?和 c=?。

应该是最佳的(在读取速度方面,而不是 size) 关联表有一个 每个方向的综合指数和 每列一个?

如果您需要在两个方向上连接,是(“每个方向上的复合索引”)和否(“每列一个”)。

幕后机制是什么?

好吧,又是同一个链接。

说到 SQL Server,您最终可能还会考虑索引视图。这是一种预加入。如上所述,两个索引也可能足够快。

【讨论】:

  • 很好的答案,谢谢。一件事:您指出两个复合索引,其中一个与另一个相反是“要做的事情”,但后来又说应该这样做并且在每一列上都有单独的索引“如果你需要双向加入”。它是哪一个?如果索引中的第一列可以像单独索引列一样使用,那么在每列上添加单个索引不是浪费时间吗?
  • 另外 - 有趣的链接,谢谢!看起来那里有一些很好的信息。问答论坛的实现似乎有点眼熟……
  • @Russ - 模糊地说,只有人失踪了。我已经编辑了上面的回复,似乎我错过了“每列一个”部分。
  • @Russ, Markus - 以相反的顺序在两列上放置覆盖索引是浪费空间。在A,BB 上拥有一个索引相当于在A,BB,A 上拥有一个索引,除非你不需要额外的索引空间和相应的更新/插入,如果你只索引一列在第二个索引中。如果他们选择两列,无论顺序如何,它将使用覆盖索引。
  • @JNK - 是和不是。首先是否:选择 B where A=?最好与覆盖物(A,B)一起使用,反之亦然。选择 select * where A=? 的情况和B =?我想说,这不是这个样本中的问题。第二部分:是的,在该示例中不应使用 INCLUDE 子句,因为如果存在覆盖索引,则覆盖索引的键无论如何都包含在非聚集索引中,因此它会自动覆盖另一列。跨度>
【解决方案2】:

在 SQL Server 中,复合索引只能用于第一列的单个字段搜索。这意味着您应该在 FK_actor_id 上有一个额外的字段索引,如果在同一查询中没有 FK_Movie_id 的情况下对该字段进行搜索。

【讨论】:

    猜你喜欢
    • 2018-09-15
    • 2015-02-13
    • 2010-10-08
    • 2011-03-07
    • 1970-01-01
    • 2011-03-03
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多