Mysql 为什么索引的使用依赖于列类型
我的问题是:Mysql 为什么索引的使用依赖于列类型,mysql,sql,optimization,indexing,Mysql,Sql,Optimization,Indexing,我的问题是: 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_conne
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_连接_三元组)的索引,其定义如下:
CREATE INDEX `temp` ON usc_connection_triple(property_id, account_connection_id, status, value);
这个复合索引工作得很好,“explain”命令还提示mysql优化器正在使用它,如下所示:
但是,只有当“value”列(类型“varchar”)长度为时,才能查看第一个执行计划,并尝试了解它是如何使用索引的 特别是额外一栏提供了非常有价值的信息: 使用Where 这意味着它需要应用一些
where
子句作为筛选谓词。也就是说,它并不是真的对所有where
子句使用这个索引,只是对其中的一些子句使用这个索引
键长度=4
在key\u len
列中,MySQL告诉我们它真正有效地使用了多少索引。4表示4个字节,通常转换为单个int
(或类似)列。这意味着,MySQL只能有效地使用索引中的第一列(property\u id
)。请参阅下面的修复建议
使用索引
返回到附加列。它实际上应该读为“仅使用索引”。这意味着索引恰好包含此查询所需的所有数据(列)。换句话说,查询不引用任何不属于索引的列。因此,MySQL不需要进行额外的IO操作来从实际表中获取更多的列。此功能也称为仅索引扫描。它可以将查询性能提高上百倍
现在是@juergend提到的限制:索引项的最大长度是有限的。对于InnoDB,每列767字节,总计3072字节。但是,如果您使用的是多字节字符集(UTF-8),则这些是字节,如您所观察到的,该数字较小
因此,当您尝试为不适合索引的内容编制索引时,MySQL将自动截断索引项以适合索引。但是,这意味着它不再在索引中存储完整的列,因此它需要额外跳到表以获取完整的列。这可以轻松将查询速度降低100倍:(
最后,最好不要使用这个索引,或者使用另一个恰好更小的索引(如您的情况)
建议
首先使用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\u id
很好,它在查询中以相等条件提到。但是,下一个索引列account\u connection\u id
在where子句中根本没有提到。这就是为什么它可以只使用下一列status
y作为过滤器
因此,第一个想法可能是重新排序索引,如下所示:
ON usc_connection_triple(property_id, status, account_connection_id, value)
这将使使用where
的消失(不过,根据MySQL版本的不同,有时不会消失)
您可能甚至会考虑把<代码>状态>代码>,因为它似乎是一个始终存在的WHERE子句。它甚至允许在某些情况下使用索引(不在您的,因为它不是<代码>命令中的第一列> < /Cult>子句)对<代码>属性Type ID /代码>进行排序。
如果无法使查询执行仅索引扫描(额外显示使用index
),则应从索引中删除where
子句中未使用的列
参考资料
最大索引长度为255感谢您提供的详细信息!我终于找到了一种方法来获取mysql optimizer使用的索引(按照您的建议更改顺序)。但有趣的是,性能仍然与索引之前相同,根本没有任何改进!对此有何建议?