如何在MySQL中为多对多连接正确索引链接表?

时间:2009-02-20 21:33:12

标签: mysql indexing many-to-many

假设我在表“table1”和“table2”之间有一个简单的多对多表,它包含两个int字段:“table1-id”和“table2-id”。我该如何索引此链接表?

我过去只创建一个复合主索引(table1-id,table2-id),但我读到如果更改查询中字段的顺序,则此索引可能不起作用。那么什么是最佳解决方案 - 为没有主索引的每个字段制作独立索引?

感谢。

3 个答案:

答案 0 :(得分:29)

这取决于您的搜索方式。

如果你这样搜索:

/* Given a value from table1, find all related values from table2 */
SELECT *
FROM table1 t1
JOIN table_table tt ON (tt.table_1 = t1.id)
JOIN table2 t2 ON (t2.id = tt.table_2)
WHERE t1.id = @id

然后你需要:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_1, table_2)

在这种情况下,table1将在NESTED LOOPS中领先,只有在table1被编入索引时,您的索引才可用。

如果你这样搜索:

/* Given a value from table2, find all related values from table1 */
SELECT *
FROM table2 t2
JOIN table_table tt ON (tt.table_2 = t2.id)
JOIN table1 t1 ON (t1.id = tt.table_1)
WHERE t2.id = @id

然后你需要:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_2, table_1)

出于上述原因。

这里不需要独立索引。可以在任何可以使用第一列上的普通索引的地方使用复合索引。如果使用独立索引,则无法有效搜索这两个值:

/* Check if relationship exists between two given values */
SELECT 1
FROM table_table
WHERE table_1 = @id1
  AND table_2 = @id2

对于这样的查询,您需要在两列上至少有一个索引。

为第二个字段添加一个额外的索引永远不会坏:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 PRIMARY KEY (table_1, table_2)
CREATE INDEX ix_table2 ON table_table (table_2)

主键将用于搜索on both values,对于基于table_1值的搜索,其他索引将用于基于table_2值的搜索。

答案 1 :(得分:5)

只要您在查询中指定两个键,它们在查询中的顺序无关紧要,也不重要在索引中指定它们的顺序。

但是,您有时只有一个或另一个键是不可能的。如果您有时只有id_1,那么这应该是第一个(但您仍然只需要一个索引)。

如果你有时有一个,有时是另一个,有时两个,你需要一个带有两个键的索引,带有一个字段的第二个(非唯一)索引 - 两个键的选择性更高 - 和主要复合索引应该从另一个键开始。

答案 2 :(得分:0)

@Quassnoi,在您的第一个查询中,您实际上只使用tt.table_1密钥,我们可以从WHERE子句中看到:WHERE t1.id = @id。在第二个查询中 - 仅tt.table_2

因此,由于WHERE table_1 = @id1 AND table_2 = @id2,多列索引仅在第三个查询中有用。如果不打算使用这种类型的查询,您认为使用两个单独的单列索引是否值得?