mysql 第5.5章 索引-什么情况下会导致索引失效 mysql 第5.5章 索引-什么情况下会导致索引失效

1天前

在 MySQL 中,有些情况可能会导致索引失效,无法有效利用索引来加速查询。以下是一些常见的导致索引失效的情况:

一、不符合最左匹配原则

当查询条件不符合最左匹配原则时,索引可能会失效。例如:

SELECT * FROM users WHERE age = 30;

如果索引是(name, age),则 age 作为查询条件在最左边列之前,因此不能有效利用该索引。

示例: 假设有一个复合索引 (name, age, city),以下查询不会使用索引:

SELECT * FROM users WHERE age = 25 AND city = 'New York';

因为没有使用到 name,复合索引失效。

解决方法:查询条件应尽量遵守最左前缀原则,首先使用最左边的列。

SELECT * FROM users WHERE name = 'John' AND age = 25;

二、使用了不支持索引的操作符

一些操作符会导致索引失效,例如:

范围查询:当查询中包含了范围查询(如 BETWEEN、<、>)但条件列未按索引顺序列出时,索引可能会失效。

SELECT * FROM users WHERE salary > 50000 AND age = 30;

函数或表达式:在查询条件中对索引列使用函数或表达式会导致索引失效。例如:

SELECT * FROM users WHERE YEAR(date_of_birth) = 1990;

这里 YEAR(date_of_birth) 使用了函数,会导致索引失效。

SELECT * FROM users WHERE YEAR(birthdate) = 2020;

在这种情况下,如果 birthdate 列上有索引,由于使用了 YEAR() 函数,索引会失效。

解决方法:避免对索引列使用函数或表达式,可以通过调整条件来使用索引。

SELECT * FROM users WHERE birthdate BETWEEN '2020-01-01' AND '2020-12-31';

三、数据类型不匹配

如果查询条件的数据类型与索引列的数据类型不匹配,索引可能会失效。例如:

SELECT * FROM users WHERE id = '123';

如果 id 是整数类型,将整数与字符串进行比较可能导致索引失效。

SELECT * FROM users WHERE phone = 1234567890;  -- phone 列为字符串类型

此处 phone 是字符串类型,但条件中的值是数字类型,可能会导致索引失效。

解决方法:保持查询条件和列的数据类型一致。

SELECT * FROM users WHERE phone = '1234567890';

四、使用 LIKE 操作符的不匹配

前缀通配符:LIKE 操作符中的前缀通配符(%)会使索引失效。例如:

SELECT * FROM users WHERE name LIKE '%Alice%';

在这种情况下,MySQL 无法使用索引来优化查询。

前缀匹配:如果 LIKE 的模式以固定字符开始(不以 % 开头),则可以利用索引。例如:

SELECT * FROM users WHERE name LIKE 'Alice%';

五、数据量过小

如果表的数据量非常小,数据库可能决定不使用索引,而是直接进行全表扫描,因为全表扫描可能更快。

六、使用 !=、<> 或者 NOT IN

这些操作符常常会导致索引失效,因为它们会导致数据库遍历大部分或全部记录。

在某些情况下,使用不等于操作符可能导致索引失效,尤其是在涉及范围查询时。例如:

SELECT * FROM users WHERE age <> 30;

解决方法:如果可能,尽量避免使用不等号,可以通过其他方式优化查询。

解决方法:如果可以,使用等值操作或者范围查询代替。

七、JOIN 操作中的索引选择

在 JOIN 操作中,如果条件列没有被正确地索引,或者索引选择不当,也可能导致索引失效。例如:

SELECT * FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE customers.name = 'Alice';

如果 orders 表的 customer_id 列没有索引,可能导致查询效率下降。

八、ORDER BY 与 GROUP BY 的顺序不一致

如果 ORDER BY 或 GROUP BY 的顺序与索引顺序不一致,可能会导致索引失效。

例 1:单列排序与索引顺序冲突

索引 idx_name_age(name, age),但查询为:

SELECT * FROM users ORDER BY age;

失效原因:索引按 name 排序后,age 在索引中是二级顺序。若按 age 排序,需先扫描整个索引(或全表),再对 age 值排序,无法直接利用索引的有序性。

例2:多列排序顺序颠倒

索引为 idx_age_name(age, name),查询为:

SELECT * FROM users ORDER BY name, age;

失效原因:索引按 age 优先排序,而查询要求先按 name 排序。顺序颠倒导致索引无法直接用于排序,需额外排序操作。

例3:索引未覆盖查询列

示例:索引为 idx_age(age),查询为:

SELECT * FROM users ORDER BY age;

失效风险:若 SELECT * 包含非索引列(如 address),数据库需回表查询完整行数据。若回表成本高,优化器可能认为全表扫描+文件排序更高效,从而放弃索引。

九、更新或删除操作

在进行大量的更新或删除操作时,索引可能会变得不再有效。如果表中的数据发生变化,索引需要进行更新和维护,以确保其正确性。

十、OR 条件不当使用

当 OR 条件中只有一部分字段上有索引,而其他字段没有索引时,索引会失效。

示例:

SELECT * FROM users WHERE name = 'John' OR age = 30;

如果 name 有索引而 age 没有索引,这种情况下索引可能失效。

解决方法:可以将 OR 改为 UNION 查询,或确保两个条件的列上都有索引。

SELECT * FROM users WHERE name = 'John'
UNION
SELECT * FROM users WHERE age = 30;

十一、过高的表数据选择性

如果一个索引列的数据选择性(即不同值的数量)过低,例如列中的大部分值相同,索引可能不会生效。因为数据库认为全表扫描的成本可能更低。

示例: 对于一个性别字段 gender,只有 M 和 F 两个值,查询时可能不会使用索引。

解决方法:对于选择性较低的列,不建议单独创建索引,可以将其与其他高选择性列组合创建复合索引。

十二、总结

了解这些导致索引失效的情况有助于在设计数据库表和编写查询时做出更合适的选择,从而提高查询性能。

索引是提高数据库查询效率的关键工具,但在某些情况下可能会失效。

开发者需要了解这些情况并合理设计查询和索引,以充分发挥索引的性能。

在实际应用中,结合具体的场景进行优化和测试,以确保索引的有效利用。

阅读 23

mysql文章
带到手机上看