(我不同意另一个答案中推荐的索引。)
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'
当优化器选择如何执行JOIN 时,它通常是这样工作的:
- 从具有最佳
WHERE 的表开始。这将是t2。所以需要有一个INDEX 以value 开头。
- 然后转到另一张桌子。唯一的下一个选择是
tt,因为这次是ON 子句。
- 之后是
t1 和t3,顺序不限。
现在是索引,按上面的顺序列出:
t2: INDEX(value)
tt: INDEX(table_2)
t1 和 t3 可以通过它们的id 访问。因此,假设您遵循id 作为PK 的约定,那么PRIMARY KEY(id) 已经存在。
现在让我们切换到新版本的查询:
SELECT t1.foo1, t2.foo2, t3.foo3 FROM tt ...
这样,我们可以制作更好的索引。 “覆盖”索引是一个INDEX,它包括查询中任何地方所需的所有列。所以,让我们添加任何此类列:
t2: INDEX(value, id, foo2)
tt: INDEX(table_2, table_3, table_1) -- table_2 must be first
在考虑“覆盖”索引时需要注意两点:
- 通过
PRIMARY KEY 进入表时,创建“覆盖”索引没有任何优势。 PK 与数据“聚集”在一起,因此有效地“覆盖”。
- 在索引中包含太多列是不“明智的”。您要求所有 (
*) 列。
有关创建最佳索引的更多信息:http://mysql.rjweb.org/doc.php/index_cookbook_mysql
唉,EXPLAIN 显示了用可用的东西做了什么;它不应该添加什么索引,也没有其他提示。
您的表格看起来不像传统的多:多表格。有关该类型表的具体提示,请参阅此:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
FOREIGN KEYs:FK 提供 (1) 约束(用于数据完整性)和 (2) INDEX 以提高检查约束的效率。当您同时创建 FK 和 INDEX 时,MySQL 可能 足够聪明,可以避免只有两个索引就足够了。 INDEX(table_2) 是 FK 所需的全部,但 INDEX(table_2, table_3, table_1) 将为该 FK “工作”。拥有两个索引是一种浪费;如果不必要地添加较短的,请删除它。