这是我的问题:
SELECT u0_.value AS value0, u1_.property_uri AS property_uri1, count(u0_.id) AS sclr2, u2_.service_id AS sclr3
FROM usc_connection_triple u0_
INNER JOIN usc_pro1_ ON u0_.property_id = u1_.id AND (u1_.status = 1)
INNER JOIN usc_account_connection u3_ ON u0_.account_connection_id = u3_.id AND (u3_.status = 1)
INNER JOIN usc_service_subscriber u2_ ON ((u2_.id = u3_.account_1_id OR u2_.id = u3_.account_2_id)) AND (u2_.status = 1)
WHERE (u1_.create_analytics = '1') AND (u0_.status = 1) GROUP BY u2_.service_id, u0_.property_id, u0_.value;
我在u0_(usc_connection_triple)上创建了一个索引,其定义如下:
CREATE INDEX `temp` ON usc_connection_triple(property_id, account_connection_id, status, value);
这个综合指数运作良好,解释'命令还显示了mysql优化器使用它的提示,如下所示:
但是,只有当'价值'列(类型' varchar')长度为< = 255。 每当我将此列修改为更高的长度时,索引的值为'长度只保留255最大值(假设是,我并不担心)和 mysql优化器完全丢弃索引(相反,它使用property_id外键索引)。 explain命令现在显示:
所以,我的问题是:
答案 0 :(得分:1)
查看第一个执行计划,并尝试了解 使用索引的方式。
特别是额外的列提供了非常有价值的信息:
使用位置
这意味着它需要将一些where
子句应用为过滤谓词。即,它并没有真正使用所有where
子句的索引,只是其中一些。
key_len = 4
在key_len
列中,MySQL告诉我们它有效地使用了多少索引。 4表示4个字节,通常转换为单个int
(或类似)列。这意味着,MySQL只能有效地使用索引中的第一列(property_id
)。请参阅下面的修复建议。
使用索引
返回 Extra 列。它实际上应该是“仅使用索引”。这意味着索引恰好具有此查询所需的所有数据(列)。换句话说,查询不引用任何不属于索引的列。因此,MySQL不需要进行额外的IO操作来从实际表中获取更多列。此功能也称为仅索引扫描。它可以提高百倍的查询性能。
现在出现了@juergend提到的限制:索引条目的最大长度是有限的。对于InnoDB,每列767个字节,总共3072个字节。但是,如果您使用的是多字节字符集(UTF-8),这些是 bytes ,数字较小 - 正如您所观察到的那样。
因此,当您尝试索引不适合索引的内容时,MySQL将默默地截断索引条目以适应。但是,这意味着它不再存储索引中的完整列,因此它需要对表进行额外跳转以获取完整列。这可以轻松地将查询速度降低100倍:(
最后,最好不要使用这个索引,或者可能是另一个恰好更小的索引(如你的情况)。
<强>建议强>
首先修复using where
部分。查看你的连接谓词:
INNER JOIN usc_pro1_ ON u0_.property_id = u1_.id AND (u1_.status = 1)
和索引
ON usc_connection_triple(property_id, account_connection_id, status, value)
只能在左侧列上使用高效索引。想象一下一本骄傲的电话簿 - 通常以姓氏,名字命名。现在尝试在这本电话簿中找到所有名字为“Sarah”的人。这里也发生了类似的问题。第一列property_id
很好,在查询中提到了相等条件。但是,where子句中根本没有提到下一个索引列account_connection_id
。这就是它可以将下一列status
仅用作过滤器的原因。
所以,第一个想法可能是重新排序索引,如下所示:
ON usc_connection_triple(property_id, status, account_connection_id, value)
这会使using where
消失(尽管,有时它不会取决于MySQL版本。)
您甚至可以考虑先放置status
,因为它似乎是一个始终存在的where子句。这甚至允许在某些情况下使用索引对property_id
进行排序(不在您的情况下,因为它不是您的order by
子句中的第一列)。
如果您无法使查询执行仅索引扫描(在额外中显示using index
),则应从索引中删除where
子句中未使用的列。
<强>参考强>