连接表的最佳SQL索引

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

模型和表格设置

我的模型是FooBar和每个轨道约定,我有一个连接表叫bars_foos 。 没有主键或时间戳使这个表中的旧字段bar_id:integerfoo_id:integer 。 我很想知道下列哪个索引是最好的,没有重复:

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

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

可能的用法

最常见的用法将被赋予一个Foo模型的实例,我将使用foo.bars的RoR语法来请求其相关的bars ,反之亦然, bar.foos用于模型Bar一个实例。

这些将生成types的查询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 = ? SELECT * FROM bars_foos where bar_id = ? AND foo_id = ?

数据库

如果有数据库特定的优化技术,我很可能会使用PostgreSQL。 然而,其他使用这个代码的人可能想要在MySQL或SQLite中使用它,这取决于他们的Railsconfiguration,所有的答案都是值得赞赏的。

答案

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

tl; dr解释

对于我的具体情况(并涵盖所有未来的基地)短tl;博士是我所怀疑的select#2 。 然而,select#3将工作得很好,因为根据我对数据的使用情况,创build复合索引所使用的额外时间和空间可以减less将来的查询查询。

充分的解释

其原因是数据库试图变得聪明,尽量尽可能快地做事情,而不pipe程序员的input。 添加索引时要考虑的最基本的项目是通过这个键来查看这个对象。 如果是,索引可能有助于加快速度。 但是,这个指标是否被使用都归结为select性和领域的基数。

由于外键通常是另一个AR类的ID,基数通常会很高。 但是,这又取决于你的数据。 在我的例子中,如果有许多Foo但很lessBar ,我的连接表中的许多条目将会有类似bar_id s。 在bar_id具有低基数的情况下, bar_id上的索引可能永远不会被使用,并且可能正在通过使数据库将时间和资源*添加到每次创build新的bars_foos条目的索引时bars_foos 。 许多Bar和less数Foo也是如此,而且都很less。

一般的教训是,当考虑表格上的索引时,决定是否将这个字段同时由这个字段查找,并且这个字段是否具有较高的基数。 那就是这个领域有很多不同的价值吗? 在大多数连接表的情况下,“这取决于”,我们必须更仔细地考虑数据代表的是什么和关系本身。 就我而言,我会同时拥有许多FooBar并且会通过关联的bar来查找Foo ,反之亦然。

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

脚注

* 有关性病指标的类似问题,有人指出,指数的成本非常低,所以如有疑问,只需加上它。

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

假设你想要search所有这些…

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

…那么你可能应该使用{bar_id, foo_id}{foo_id}上的索引。

虽然您可以在{bar_id}上创build第三个索引,但维护附加索引的价格可能会超过较小索引中更好聚类的好处。


另外,你如何计划用索引来涵盖你的查询? 一些替代品,如…

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

…可能会更好地覆盖某些types的查询。

覆盖是一个平衡的行为 – 有时只是为了覆盖目的而将一个字段添加到索引是有道理的,有时不是。 直到您测量实际的数据量时,您才会知道。

(免责声明:我不熟悉Ruby,这个答案完全是从数据库的angular度来看的。)