连接表的最佳SQL索引

Aar*_*ron 38 indexing database-design ruby-on-rails 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的组合

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

可能的用法

最常见的用法将给出一个模型实例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应用程序的上下文中,它会尝试进行查询,其中指定两个ID SELECT * FROM bars_foos where bar_id = ? AND foo_id = ?.

数据库

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

Aar*_*ron 32

答案

重复的答案往往总是如此,"这取决于".更具体地说,它取决于您的数据是什么以及如何使用它.

tl; dr解释

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

完整解释

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

由于外键通常是另一个AR类的ID,因此基数通常很高.但同样,这取决于您的数据.在我的例子中,如果有很多Foo但很少的Bars,我的连接表中的许多条目将具有simliar bar_id.如果bar_ids具有较低的基数,则bar_id可能永远不会使用索引,并且可能通过让数据库每次bars_foos创建新条目时将时间和资源*添加到该索引来妨碍索引.许多Bars和少数Foo两者都是如此.

一般的教训是,在考虑表上的索引时,确定是否将通过该字段查找条目以及该字段是否具有高基数.也就是说,这个领域有很多不同的价值吗?在大多数连接表"依赖于"的情况下,我们必须更仔细地考虑数据代表什么和关系本身.就我而言,我将有两个FooS和BarS和将查找Foo通过其相连的S barS和反之亦然.

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

脚注

*在关于STI指数的类似问题中,有人指出指数的成本非常低,所以如有疑问,只需添加即可.


Bra*_*vic 5

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

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

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

...那么你应该选择索引{bar_id, foo_id}和索引{foo_id}.

虽然您可以创建第三个索引{bar_id},但维持额外索引的价格可能会超过较小索引中更好聚类的好处.


另外,您打算如何使用索引覆盖查询?一些替代品,例如......

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

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

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

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