考虑到性能方面的改进,我想知道是否以及哪些索引对连接表有帮助(特别是在Rails 3 has_and_belongs_to_many上下文中使用)。
我的模型是Foo
和Bar
以及每个rails约定,我有一个名为bars_foos
的连接表。此表bar_id:integer
和foo_id:integer
中的旧字段没有主键或时间戳。我很想知道以下哪个索引最好而且没有重复:
add_index :bars_foos, [:bar_id, :foo_id]
add_index :bars_foos, :bar_id
add_index :bars_foos, :foo_id
基本上,我不确定复合索引是否足够,假设它有助于开始。我相信复合索引可以用作第一项的单个索引,这就是为什么我非常确保使用所有三行肯定会导致不必要的重复。
最常见的用法是获得模型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配置,以便所有答案都受到赞赏。
答案 0 :(得分:32)
经常重复的答案往往是这种情况,“这取决于”。更具体地说,它取决于您的数据是什么以及如何使用它。
我的具体案例(以及涵盖所有未来基础)的短期答案是选择#2 ,这是我怀疑的。但是,选择#3可以正常工作,因为根据我对数据的使用情况,创建复合索引所使用的额外时间和空间可能会减少将来的查询查找。
这样做的原因是数据库试图变得聪明,并且无论程序员输入如何,都尽可能快地做事。添加索引时要考虑的最基本的项目是通过此键查找此对象。如果是,索引可以帮助加快速度。然而,这个指数是否均被使用都取决于选择性和该领域的基数。
由于外键通常是另一个AR类的ID,因此基数通常很高。但同样,这取决于您的数据。在我的示例中,如果有很多Foo
但很少Bar
s,则我的联接表中的许多条目都会有bar_id
个。如果bar_id
具有较低的基数,则bar_id
上的索引可能永远不会被使用,并且可能会因为数据库每次为新{添加时间和资源*添加到此索引而妨碍创建了{1}}条目。同样适用于许多bars_foos
和少数Bar
以及两者中的少数。
一般的教训是,在考虑表上的索引时,确定是否将通过此字段查找条目以及此字段是否具有高基数。也就是说,这个领域有很多不同的价值吗?在大多数连接表“依赖于”的情况下,我们必须更仔细地考虑数据代表什么和关系本身。在我的情况下,我将两个许多Foo
和Foo
s,并且将通过关联的Bar
和Foo
来查找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。这个答案纯粹是从数据库的角度来看。)