【问题标题】:Is composite index really necessary for a table with composite primary key?具有复合主键的表真的需要复合索引吗?
【发布时间】:2012-06-23 04:37:13
【问题描述】:

假设我们有一个表来存储用户最喜欢的图片,并带有一个复合主键对(UserId,PictureId)。书籍通常说在这种情况下您需要一个基于 (UserId, PictureId) 的复合索引,它通常在 WHERE 子句中显示为 (UserId=103 AND PictureId=1234)。但我认为 dababase 引擎应该足够聪明,可以分别使用基于两列的两个单独的索引。只需从每个索引中获取一组行号,然后找到两组中都存在的行号。这样,就不需要复合索引了。

那么,实际上数据库引擎可以做到这一点吗?

【问题讨论】:

  • 如果您使用的是复合 PK,那么您的所有 FK 都需要包含 all PK - 句点的列。毕竟:如果您使用这两列作为您的 PK,那么只有这两列的 组合 才能唯一标识一行 - 对吧?如果不是:那么您的 PK 是错误的 - 也许您甚至不需要复合 PK - 单独的一列将可靠且唯一地每一行?然后只使用那一列作为您的 PK。
  • @marc_s:这是表之间“多对多”关系的情况,您需要第三张表作为中间的复合主键。
  • 好的,但在这种情况下 - 您需要在 UserID 上创建一个索引,在 PictureId 上创建第二个单独的索引(以加快 JOIN 到所涉及的其他表的速度),您可能需要一个(UserID, PictureId) 对的唯一约束以避免重复。在这种情况下,在我看来,两列上的 复合主键 没有意义。

标签: sql


【解决方案1】:

使用两个单独的单列索引没有任何优势;引擎最好进行表扫描。

使用索引的目的是使访问更快。如果引擎使用两个索引,则必须从其中一个索引中对至少一组数据进行排序,并合并来自这两个索引的结果。这比只读取一个复合索引要多得多,尤其是因为复合索引允许只进行索引扫描。

【讨论】:

  • 如果您尝试通过 ID 查找单个图像怎么办(一个合理的用例)。那么图片id上的单列索引不是有用吗?
  • 如果你说的是真的,我对此表示怀疑,那么每当 WHERE 子句中存在“AND”条件时,出现在 WHERE 子句中的单个列的所有索引都是无用的。但我同意使用两个单列索引而不是复合索引键不会提高性能。
  • SQL Server 能够连接两个或多个单独的索引并将它们相交,就像您使用复合索引一样,为您提供单一索引和复合索引的最佳优势。sql-server-performance.com/2007/composite-indexes跨度>
【解决方案2】:

大多数数据库引擎将要求复合索引来强制主键。因此,无论如何,它都是一个“免费”索引 - 为什么要担心它?

PictureID 上添加第二个索引可能有一些好处(如果索引在UserID,PictureID 上)。仅针对 UserID 的任何查询都可以使用复合索引,而仅使用 PictureID 的查询将无法这样做。

【讨论】:

    【解决方案3】:

    我认为在您描述的用例中,复合索引不是必需的。如果您对一组给定的用户 ID 加上一组给定的图片 ID 进行查询,这将很有用。但是你什么时候需要它?您更有可能查询给定日期范围内的所有用户图片,或按 ID 查找特定图片。这将建议一个复合 user id + date 索引和另一个 picture id 仅索引的索引结构。

    这始终取决于您数据库中记录的分布情况,以及您最常运行的查询类型。

    【讨论】:

      【解决方案4】:

      PRIMARY KEY 或 UNIQUE 约束是抽象的理论概念。

      索引是实际生活在现实世界中的物理事物。

      实际上,索引可用于强制执行 PK 或 UNIQUE 约束。但也可以使用其他技术(例如,对于小域:位图)

      【讨论】:

        【解决方案5】:

        你描述的会比使用复合索引贵很多。

        首先需要从第一个索引中识别一组行,然后从第二个索引中识别一组行,最后在两者之间执行集合交集。

        --- 更新 ---

        请注意,这是您为每个 INSERT/UPDATE 和每个外键检查支付的价格,而不仅仅是SELECT。

        此外,还可能涉及并发问题 - 根据 DBMS 的实施方式,通过单个唯一复合索引强制唯一性可能比通过两个非唯一、非复合索引强制唯一性需要更少/更简单的锁定。

        当然,如果您打算 cluster 您的表,主索引通常也是聚集索引,并且无论如何都包含所有列,因此从“排序”中排除任何内容没有太大意义索引的一部分。

        【讨论】:

        • 向我描述一下为什么会贵?通过索引检查一点也不昂贵,因为 B 树适合随机访问。您认为 TWICE 通读一本书的目录和通读一本书一样昂贵吗?
        • @Aperture 这将是 2 次索引范围扫描,而不是 1 次索引搜索。并且集合交叉点也有一些成本。不,我不这么认为,我也没有这么说。从我回答的措辞很明显,我将它与复合索引而不是表扫描进行比较。
        • 我的朋友,想想看,无论你搜索多少个 B-tree 索引,它永远不会是执行全表扫描所需时间的一小部分。此外,与对一百万条记录的全表扫描相比,IMO 使用聚集索引和非聚集索引之间的差异太小了。只是我的想法。
        • @Aperture 你在说什么?为什么还要提到表扫描?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-11
        • 1970-01-01
        • 1970-01-01
        • 2013-04-30
        • 1970-01-01
        • 2013-12-19
        • 1970-01-01
        相关资源
        最近更新 更多