MySQL 带连接的索引顺序
MySQL index order with joins
我正在尝试正确设置索引中的列顺序,但尚未看到对此的直接回答。如果我们有如下查询
SELECT ... all the things ...
FROM tb_contact
inner join tb_contact_association on tb_contact.id = tb_contact_association.attached_id
where tb_contact_association.contact_id = '498'
order by ...
我们正在查看此联接的枢轴 table、tb_contact_association。如果不同时查看 attached_id(连接)和 contact_id(位置),就永远不会真正查询此 table。
在为 tb_contact_association 创建索引时,索引是否应该按顺序同时包含 "attached_id,contact_id"?首先加入,然后在哪里?或者反过来?还是他们每个人单独?
谢谢。
通常,索引中字段的顺序并不重要,如果您使用适当的字段。
例如对于这样的查询:
SELECT .. WHERE f1 = 'a' AND f2 = 'b' AND f3 = 'c'
INDEX(f3, f2, f1) - index can be used
INDEX(f1, f3, f1) - can be used
INDEX(f1, f2, f3) - can be used
INDEX(f1, f3) - completely usable
INDEX(f3, f1) - completely usable
INDEX(f4, f1) - cannot be used - no 'f4' field in the where clause
INDEX(f1, f4) - can be used, because 'f1' is in the where clause, but f4
component will be ignored
WHERE
子句的实际顺序无关紧要。 WHERE f1 = 'a' AND f2 = 'b'
v.s。 WHERE f2 = 'b' AND f1 = 'a'
就查询 compiler/optimizer 而言是相同的。
最有可能的是,这两个字段都应该有一个索引。但是在这个查询中,只有 contact_id 需要索引,Nathan 的回答更详细地解释了原因。
您的特定查询的最佳索引是 (contact_id, attached_id).
所需的索引取决于连接的方向 运行。您可以通过 运行 在您的 select 语句中使用 EXPLAIN 来确定这一点。但是在这种情况下,由于您的 WHERE 子句在 tb_contact_association table 上过滤,优化器很可能会以此 table 开始并加入 tb_contact table.
例外情况是 tb_contact 与 tb_contact_association 相比较小(几行)。要了解为什么会这样,请考虑一个极端的例子。如果tb_contact只有一行长,从那一行开始显然会更快,加入tb_contact_associationtable中对应的行,然后测试它的值为[=30] =],而不是遍历整个更大的 tb_contact_association table 寻找 contact_id=498(即使有索引),然后加入回 tb_contact table.
但是,对于任何正常的 table,上面的查询将以 tb_contact_association 开头。对于连接,您需要在要连接 到 的列上建立索引。在本例中,即 tb_contact.id。您还需要一个索引来帮助您的 WHERE 子句,即 tb_contact_association.contact_id.
对于这个特定的查询,您实际上不需要在 tb_contact_association.attached_id 上建立索引,只要连接总是按照我们期望的方向进行即可。 tb_contact_association 中 (contact_id、attached_id)(按此顺序)的复合索引应该会有一点帮助,因为它将允许 table 的所有必要信息直接从索引中提取,为每一行保存从数据 table 中读取的内容。 (添加此索引后,您应该在查询 EXPLAIN 的额外部分中看到 "using index"。)contact_id 列用于 WHERE 子句,就像该列上的单个索引一样,但是复合索引,然后它可以直接从索引读取 attached_id,而不是从 table.
我正在尝试正确设置索引中的列顺序,但尚未看到对此的直接回答。如果我们有如下查询
SELECT ... all the things ...
FROM tb_contact
inner join tb_contact_association on tb_contact.id = tb_contact_association.attached_id
where tb_contact_association.contact_id = '498'
order by ...
我们正在查看此联接的枢轴 table、tb_contact_association。如果不同时查看 attached_id(连接)和 contact_id(位置),就永远不会真正查询此 table。
在为 tb_contact_association 创建索引时,索引是否应该按顺序同时包含 "attached_id,contact_id"?首先加入,然后在哪里?或者反过来?还是他们每个人单独?
谢谢。
通常,索引中字段的顺序并不重要,如果您使用适当的字段。
例如对于这样的查询:
SELECT .. WHERE f1 = 'a' AND f2 = 'b' AND f3 = 'c'
INDEX(f3, f2, f1) - index can be used
INDEX(f1, f3, f1) - can be used
INDEX(f1, f2, f3) - can be used
INDEX(f1, f3) - completely usable
INDEX(f3, f1) - completely usable
INDEX(f4, f1) - cannot be used - no 'f4' field in the where clause
INDEX(f1, f4) - can be used, because 'f1' is in the where clause, but f4
component will be ignored
WHERE
子句的实际顺序无关紧要。 WHERE f1 = 'a' AND f2 = 'b'
v.s。 WHERE f2 = 'b' AND f1 = 'a'
就查询 compiler/optimizer 而言是相同的。
最有可能的是,这两个字段都应该有一个索引。但是在这个查询中,只有 contact_id 需要索引,Nathan 的回答更详细地解释了原因。
您的特定查询的最佳索引是 (contact_id, attached_id).
所需的索引取决于连接的方向 运行。您可以通过 运行 在您的 select 语句中使用 EXPLAIN 来确定这一点。但是在这种情况下,由于您的 WHERE 子句在 tb_contact_association table 上过滤,优化器很可能会以此 table 开始并加入 tb_contact table.
例外情况是 tb_contact 与 tb_contact_association 相比较小(几行)。要了解为什么会这样,请考虑一个极端的例子。如果tb_contact只有一行长,从那一行开始显然会更快,加入tb_contact_associationtable中对应的行,然后测试它的值为[=30] =],而不是遍历整个更大的 tb_contact_association table 寻找 contact_id=498(即使有索引),然后加入回 tb_contact table.
但是,对于任何正常的 table,上面的查询将以 tb_contact_association 开头。对于连接,您需要在要连接 到 的列上建立索引。在本例中,即 tb_contact.id。您还需要一个索引来帮助您的 WHERE 子句,即 tb_contact_association.contact_id.
对于这个特定的查询,您实际上不需要在 tb_contact_association.attached_id 上建立索引,只要连接总是按照我们期望的方向进行即可。 tb_contact_association 中 (contact_id、attached_id)(按此顺序)的复合索引应该会有一点帮助,因为它将允许 table 的所有必要信息直接从索引中提取,为每一行保存从数据 table 中读取的内容。 (添加此索引后,您应该在查询 EXPLAIN 的额外部分中看到 "using index"。)contact_id 列用于 WHERE 子句,就像该列上的单个索引一样,但是复合索引,然后它可以直接从索引读取 attached_id,而不是从 table.