连接表的最佳SQL索引

时间:2012-05-28 21:20:37

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

考虑到性能方面的改进,我想知道是否以及哪些索引对连接表有帮助(特别是在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]
    • 两个索引
    • 甲。 add_index :bars_foos, :bar_id
    • B中。 add_index :bars_foos, :foo_id
  2. 1和2-B的组合
  3. 基本上,我不确定复合索引是否足够,假设它有助于开始。我相信复合索引可以用作第一项的单个索引,这就是为什么我非常确保使用所有三行肯定会导致不必要的重复。

    可能的用法

    最常见的用法是获得模型Foo的实例,我将使用bars的RoR语法询问其关联的foo.bars,反之亦然bar.foos }对于模型Bar的实例。

    这些将分别生成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 (?)

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

    数据库

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

2 个答案:

答案 0 :(得分:32)

答案

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

tl; dr说明

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

完整解释

这样做的原因是数据库试图变得聪明,并且无论程序员输入如何,都尽可能快地做事。添加索引时要考虑的最基本的项目是通过此键查找此对象。如果是,索引可以帮助加快速度。然而,这个指数是否均被使用都取决于选择性和该领域的基数。

由于外键通常是另一个AR类的ID,因此基数通常很高。但同样,这取决于您的数据。在我的示例中,如果有很多Foo但很少Bar s,则我的联接表中的许多条目都会有bar_id个。如果bar_id具有较低的基数,则bar_id上的索引可能永远不会被使用,并且可能会因为数据库每次为新{添加时间和资源*添加到此索引而妨碍创建了{1}}条目。同样适用于许多bars_foos和少数Bar以及两者中的少数。

一般的教训是,在考虑表上的索引时,确定是否将通过此字段查找条目以及此字段是否具有高基数。也就是说,这个领域有很多不同的价值吗?在大多数连接表“依赖于”的情况下,我们必须更仔细地考虑数据代表什么和关系本身。在我的情况下,我将两个许多FooFoo s,并且将通过关联的BarFoo来查找bar个反之亦然。

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

脚注

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

答案 1 :(得分:5)

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

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

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

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

虽然 也可以<{1}}创建第三个索引,但维护其他索引的价格可能会超过较小索引中更好clustering的好处。


另外,您如何计划使用索引cover查询?一些替代方案,例如......

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

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

覆盖是一种平衡行为 - 有时为了覆盖目的而在索引中添加字段是合理的,有时则不然。在您衡量实际数据量之前,您不会知道。

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