复合索引是否适用于连接(多对多)?

And*_*nko 0 mysql sql indexing join query-optimization

tt - 是一个映射表。 tt结构是

表_1 | 表_2 | 表3

   SELECT t1.foo1, t2.foo2, t3.foo3 FROM tt 
        JOIN table1 t1 ON tt.table_1 = t1.id
        JOIN table2 t2 ON tt.table_2 = t2.id
        JOIN table3 t3 ON tt.table_3 = t3.id
    WHERE t2.value = 'test'
Run Code Online (Sandbox Code Playgroud)

该指数是否有意义并且会发挥作用tt?综合指数为ix_table_1__table_2__table_3(table1, table2, table_3)

如果这样做 - 为什么,如果不这样做 - 为什么?

Ric*_*mes 5

(我不同意另一个答案中推荐的索引。)

SELECT * FROM tt 
    JOIN table1 t1 ON tt.table_1 = t1.id
    JOIN table2 t2 ON tt.table_2 = t2.id
    JOIN table3 t3 ON tt.table_3 = t3.id
WHERE t2.value = 'test'
Run Code Online (Sandbox Code Playgroud)

当优化器选择如何执行 a 时JOIN,它通常会这样工作:

  1. 从最好的表开始WHERE。这将是t2。所以需要以INDEX 开头value
  2. 然后移动到彼此的桌子上。下一个选择只有tt,因为ON这次有条款。
  3. 之后t1t3,按任一顺序。

现在按上面的顺序列出索引:

t2:  INDEX(value)
tt:  INDEX(table_2)
Run Code Online (Sandbox Code Playgroud)

t1t3通过他们的id. id所以,假设你遵循成为 PK的惯例,那么PRIMARY KEY(id)就已经存在了。

现在让我们切换到新版本的查询:

SELECT t1.foo1, t2.foo2, t3.foo3 FROM tt  ...
Run Code Online (Sandbox Code Playgroud)

这样,我们就可以制作更好的索引。“覆盖”索引是INDEX包含查询中任何位置所需的所有列的索引。因此,让我们添加任何此类列:

t2:  INDEX(value, id, foo2)
tt:  INDEX(table_2, table_3, table_1)  -- table_2 must be first
Run Code Online (Sandbox Code Playgroud)

考虑“覆盖”索引时需要注意两件事:

  • 当通过 访问表时PRIMARY KEY,创建“覆盖”索引没有任何优势。PK 与数据“聚集”,因此有效地“覆盖”。
  • 索引中包含太多列并不“明智”。您要求提供所有 ( *) 列。

有关创建最佳索引的更多信息:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

唉,EXPLAIN显示了用可用的东西做了什么;它没有说明应该添加什么索引,也没有其他提示。

您的表格看起来不像传统的“many:many”表格。有关该类型表的具体提示,请参阅: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

FOREIGN KEYs:FK 提供 (1) 约束(用于数据完整性)和 (2) 使INDEX检查该约束变得高效。当您同时创建 FKINDEX,MySQL可能会足够聪明,在仅需要 2 个索引的情况下避免使用 2 个索引。 INDEX(table_2)是 FK 所需要的一切,但INDEX(table_2, table_3, table_1)会为该 FK“工作”。拥有这两个索引是一种浪费;如果不需要添加较短的,请将其删除。