MySQL 查询条件使用>=不走索引的主要原因是优化器基于成本的判断。当查询数据量超过表数据的 10%-30% 时,全表扫描成本低于索引扫描。此外,隐式类型转换、索引列上使用函数、违背最左前缀原则、使用 OR 连接无索引列等情况也会导致索引失效。优化方案包括:确保查询条件类型与字段一致,避免对索引列计算,遵循联合索引最左匹配,以及使用 EXPLAIN 分析执行计划,必要时强制使用索引或重写 SQL 拆分查询。
索引失效的情况有哪些?索引何时会失效?(全面总结)
虽然你这列上建了索引,查询条件也是索引列,但最终执行计划没有走它的索引。select*from test where id=c_id; 这种情况会被认为还不如走全表扫描。我们在设计数据库表时,应该尽力避免 NULL 值出现,如果非要不可避免的要出现 NULL 值,也要给一个 DEFAULT 值,数值型可以给 0、-1 之类的,字符串有时候给空串有问题,就给一个空格或其他。如果索引列是可空的,是不会给其建索引的,索引值是少于表的 count(*) 值的,所以这种情况下,执行计划自然就去扫描全表了。我们知道建立索引时,给每一个索引列建立一个条目,如果查询条件为等值或范围查询时,索引可以根据查询条件去找对应的条目。反过来当查询条件为非时,索引定位就困难了,执行计划此时可能更倾向于全表扫描,这类的查询条件有:<>、NOT、in、not exists 当使用模糊搜索时,尽量采用后置的通配符,例如:name||'%',因为走索引时,其会从前去匹配索引列,这时候是可以找到的,如果采用前匹配,那么查索引就会很麻烦,比如查询所有姓张的人,就可以去搜索'张%'。相反如果你查询所有叫'明'的人,那么只能是%明。所以业务设计的时候,尽量考虑到模糊搜索的问题,要更多的使用后置通配符。查询条件上尽量不要对索引列使用函数,比如下面这个 SQL select*from test whereupper(name)='SUNYANG'; 这样是不会走索引的,因为索引在建立时会和计算后可能不同,无法定位到索引。但如果查询条件不是对索引列进行计算,那么依然可以走索引。select*from test where name=upper('sunyang');--INDEXRANGESCAN
mysql 索引失效场景及解决方案
一、查询条件不满足最左匹配原则 场景:复合索引 (a, b, c) 在以下查询中失效:代码语言:javascript AI 代码解释 --未从索引首列开始 SELECT*FROMtableWHEREb=1ANDc=2;--跳过中间列 SELECT*FROMtableWHEREa=1ANDc=2; 解决方案:确保查询条件从复合索引的最左列开始 调整索引顺序以匹配常用查询模式 二、在索引列上使用函数或表达式 代码语言:javascript AI 代码解释 --使用函数 SELECT*FROMtableWHEREYEAR(create_time)=2023;--使用表达式 SELECT*FROMtableWHEREprice*1.1>100; 解决方案:代码语言:txt AI 代码解释 将计算移到查询条件右侧:sql SELECT * FROM table WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01'; SELECT * FROM table WHERE price > 100 / 1.1; 三、隐式类型转换导致索引失效 代码语言:javascript AI 代码解释 --字段类型为 VARCHAR,但查询时未加引号 SELECT*FROMtableWHEREphone=13800138000;--字段类型为 INT,但查询时加了引号 SELECT*FROMtableWHEREid='123'; 解决方案:确保查询条件中的数据类型与字段类型一致 使用 EXPLAIN 检查是否存在类型转换 四、使用 LIKE 通配符开头 代码语言:javascript AI 代码解释 SELECT*FROMtableWHEREnameLIKE'%keyword'; 解决方案:代码语言:txt AI 代码解释 避免通配符开头,改用:sql SELECT * FROM table WHERE name LIKE 'keyword%'; 若必须支持双向搜索,可考虑:全文索引 (FULLTEXT) 应用层预处理 (如建立反向索引) 五、OR 条件导致索引失效 代码语言:javascript AI 代码解释 SELECT*FROMtableWHEREa=1ORb=2; 解决方案:代码语言:txt AI 代码解释 若 a 和 b 均有独立索引,可拆分为 UNION:sql SELECT * FROM table WHERE a = 1 UNION SELECT * FROM table WHERE b = 2; 为 (a, b) 创建复合索引 六、索引字段参与 NULL 值比较 代码语言:javascript AI 代码解释 SELECT*FROMtableWHEREcolumnISNULL;SELECT*FROMtableWHEREcolumnISNOTNULL; 解决方案:若查询频繁,可为字段添加 NOT NULL 约束 代码语言:txt AI 代码解释 对 IS NULL 条件创建索引:sql CREATE INDEX idx_column ON table (column); 七、范围查询导致后续索引列失效 场景:场景:复合索引 (a, b, c) 在以下查询中 b 和 c 索引失效:
谈谈 MYSQL 索引失效场景
MySQL 中提高性能的一个最有效的方式是对数据表设计合理的索引。索引提供了访问高效数据的方法,并且加快查询的速度,因此索引对查询的速度有着至关重要的影响。使用索引可以快速地定位表中的某条记录,从而提高数据库查询的速度,提高数据库的性能。如果查询时没有使用索引,查询语句就会扫描表中的所有记录。在数据量大的情况下,这样查询的速度会很慢。大多数情况下都 (默认) 采用 B+ 树来构建索引。只是空间列类型的索引使用 R-树,并且 MEMORY 表还支持 hash 索引。其实,用不用索引,最终都是优化器说了算。优化器是基于什么的优化器?基于 cost 开销 (CostBaseOptimizer),它不是基于规则 (Rule-BasedOptimizer),也不是基于语义。怎么样开销小就怎么来。另外,SQL 语句是否使用索引,跟数据库版本、数据量、数据选择度都有关系。当 Mysql 使用索引的要扫描行记录数超过全表的 10%-30% 时,优化器可能会放弃走索引。隐式类型转换 隐式类型转换会导致索引失效,比如当查询条件类型为数值时,将字符串类型转换为浮点型可能会将索引数据无效。解决方式是统一设置字段类型。代码语言:javascript AI 代码解释 select*from table_name t1 left join table_name2 t2 on t1.id=t2.tid; 如果 t1 表的 id 类型和 t2 表的 tid 类型不一致的时候,就无法按索引执行 索引列上使用函数 索引列上使用函数是因为索引保存的是索引字段的原始值,而不是经过函数计算后的值,所以无法使用索引。代码语言:javascript AI 代码解释 SELECT*FROM`user`WHEREDATE(create_time)='2023-11-29'; 非最左匹配 非最左匹配指的是查询不满足最左前缀原则中的最左边的匹配要求,即查询字段不能包含联合索引中的所有索引字段。最左前缀原则是 MySQL 中的最佳左前缀原则,通过使用联合索引可以避免最左边的匹配问题。因此,如果查询字段包含联合索引,则应优先选择使用最左前缀原则
个 MySQL 慢查询的原因分析「建议收藏」
1. SQL 没加索引如果没有加索引的话,会导致全表扫描的。因此,应考虑在 where 的条件列,建立索引,尽量避免全表扫描。select * from user_info where name ='捡田螺的小男孩公众号' ; //添加索引 alter table user_info add index idx_name (name); 有时候我们明明加了索引了,但是索引却不生效。userId 字段为字串类型,是 B + 树的普通索引,如果查询条件传了一个数字过去,会导致索引失效。如果给数字加上”, 也就是说,传的是一个字符串呢,当然是走索引,如下图:这是因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL 会做隐式的类型转换,把它们转换为浮点数再做比较。隐式的类型转换,索引会失效。我们还是用这个表结构:其中 userId 加了索引,但是 age 没有加索引的。对于 or+ 没有索引的 age 这种情况,假设它走了 userId 的索引,但是走到 age 查询条件时,它还得全表扫描,也就是需要三步过程:全表扫描 + 索引扫描 + 合并。如果它一开始就走全表扫描,直接一遍扫描就完事。但是平时大家使用的时候,还是要注意一下这个 or,学会用 explain 分析。遇到不走索引的时候,考虑拆开两条 SQL。
FAQ
问:为什么加了索引查询还是慢?
答:可能索引失效,如类型不匹配或使用了函数。
问:如何确认索引是否生效?
答:使用 EXPLAIN 命令查看执行计划。
问:范围查询会影响后续索引列吗?
答:会,联合索引中范围查询后的列索引失效。