【问题标题】:Best SQL indexes for join table连接表的最佳 SQL 索引
【发布时间】:2012-06-03 04:00:50
【问题描述】:

考虑到性能改进,我想知道哪些索引对连接表有帮助(特别是在 Rails 3 has_and_belongs_to_many 上下文中使用)。

模型和表格设置

我的模型是FooBar,根据rails 约定,我有一个名为bars_foos 的连接表。没有主键或时间戳使该表中的旧字段bar_id:integerfoo_id:integer。我有兴趣了解以下哪些索引是最好的并且没有重复:

  1. 复合索引:add_index :bars_foos, [:bar_id, :foo_id]
    • 两个索引
    • A. add_index :bars_foos, :bar_id
    • 乙。 add_index :bars_foos, :foo_id
  2. 1 和 2-B 的组合

基本上,我不确定复合索引是否足够,假设它有助于开始。我相信复合索引可以用作第一项的单个索引,这就是为什么我漂亮确信使用所有三行肯定会导致不必要的重复。

可能的用途

最常见的用法是模型Foo的实例,我将使用foo.bars的RoR语法询问其关联的bars,反之亦然,bar.foos是模型@的实例987654333@.

这些将分别生成SELECT * FROM bars_foos WHERE foo_id = ?SELECT * FROM bars_foos WHERE bar_id = ? 类型的查询,然后将这些结果ID 用于SELECT * FROM bars WHERE ID in (?)SELECT * FROM foos WHERE ID in (?)

如果我不正确,请在 cmets 中纠正我,但我不相信,在 Rails 应用程序的上下文中,它会尝试执行一个查询,其中指定两个 ID,如 SELECT * FROM bars_foos where bar_id = ? AND foo_id = ?

数据库

如果有特定于数据库的优化技术,我很可能会使用 PostgreSQL。但是,其他使用此代码的人可能希望根据他们的 Rails 配置在 MySQL 或 SQLite 中使用它,因此所有答案都值得赞赏。

【问题讨论】:

    标签: ruby-on-rails database-design indexing rails-migrations


    【解决方案1】:

    答案

    经常重复的答案是“视情况而定”,这种情况往往总是如此。更具体地说,这取决于您的数据是什么以及如何使用。

    tl;dr 解释

    我的具体案例(并涵盖所有未来的基础)的简短 tl;dr 答案是 选择 #2,这是我所怀疑的。但是,选择 #3 可以正常工作,因为根据我对数据的使用情况,创建复合索引所用的额外时间和空间可能会减少未来的查询查找。

    完整解释

    这样做的原因是数据库试图变得聪明,并试图尽可能快地做事,而不管程序员的输入如何。添加索引时要考虑的最基本的项目是是否会通过此键查找此对象。如果是,索引可能有助于加快速度。但是,这个索引是否被使用都归结为选择性和字段的基数。

    由于外键通常是另一个 AR 类的 ID,因此基数通常会很高。但同样,这取决于您的数据。在我的示例中,如果有很多Foos 但很少有Bars,我的连接表中的许多条目将具有类似的bar_ids。由于bar_ids 具有低基数,bar_id 上的索引可能永远不会被使用,并且可能会因为每次有新的bars_foos 条目时让数据库投入时间和资源* 来添加到该索引而受到阻碍创建的。许多Bars 和少数Foos 以及两者都很少。

    一般的教训是,在考虑表上的索引时,要确定条目是否都将由该字段查找,以及该字段是否具有高基数。也就是说,这个字段有很多不同的值吗?在大多数连接表的情况下,“这取决于”,我们必须更仔细地考虑数据代表什么以及关系本身。就我而言,我将拥有许多Foos 和Bars,并且将通过它们关联的bars 查找Foos,反之亦然。

    我在办公室得到的另一个好答案是,“你为什么要担心你的索引?构建你的应用程序!”

    脚注

    * 在一个类似的问题on indexes on STI 中指出索引的成本非常低,所以如果有疑问,只需添加它。

    【讨论】:

      【解决方案2】:

      取决于您将如何查询数据。

      假设您要搜索所有这些...

      • WHERE bar_id = ?
      • WHERE foo_id = ?
      • WHERE bar_id = ? AND foo_id = ?

      ...那么您可能应该使用{bar_id, foo_id} 上的索引和{foo_id} 上的索引。

      虽然您也可以{bar_id} 上创建第三个索引,但维护额外索引的代价可能会超过在较小索引中使用更好的clustering 所带来的好处。


      另外,您打算如何使用索引来cover 您的查询?一些替代方案,例如...

      • {foo_id, bar_id}{bar_id}
      • {foo_id, bar_id}{bar_id, foo_id}

      ...可能更好地涵盖某些类型的查询。

      覆盖是一种平衡行为 - 有时仅出于覆盖目的将字段添加到索引是合理的,有时则不然。在您衡量真实的数据量之前,您不会知道。

      (免责声明:我不熟悉 Ruby。这个答案纯粹是从数据库的角度来看。)

      【讨论】:

      • 感谢布兰科的回答。此连接表对于 FooBar 模型之间的 has 和属于许多关系是必需的。我更新了这个问题,以进一步探讨从 Rails 模型生成的典型查询。它开始看起来像 bar_id 上的简单索引,而 foo_id 可能是我需要的。 [:bar_id, :foo_id] 上的复合可能有用,因为它可以额外防止重复,但可能是不必要的。
      猜你喜欢
      • 1970-01-01
      • 2013-03-29
      • 2013-12-01
      • 1970-01-01
      • 2011-05-03
      • 2017-02-22
      • 2014-09-19
      • 2017-01-08
      • 2010-09-08
      相关资源
      最近更新 更多