首页 > 数据库 >【MySQL优化】索引失效的场景

【MySQL优化】索引失效的场景

时间:2023-09-14 17:11:38浏览次数:38  
标签:索引 key MySQL employee 失效 +----+-------------+------------+------------+------+--

目录

索引失效场景

假设存在如下表:

CREATE TABLE `t_employee` (
  `id` int NOT NULL,
  `name` char(64) DEFAULT NULL,
  `entity_id` int DEFAULT NULL,
  `class_id` int DEFAULT NULL,
  `department_id` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `entity_idx` (`entity_id`,`class_id`,`department_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

未遵循最左前缀匹配导致索引失效

模糊查询时(like语句),模糊匹配的占位符位于条件的首部,如下所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE name LIKE "%snow";
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

联合索引不遵循最左前缀,如下所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE class_id = 1;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM t_employee WHERE class_id = 1 AND department_id = 2;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

索引列参与运算

如果索引列参与了运算,会导致索引失效,引发全表扫描,如下所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE id + 1 = 10;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

索引列使用了函数

mysql> EXPLAIN SELECT * FROM t_employee WHERE LEFT(name, 4) = "snow";
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

类型转换导致索引失效

  • 类型隐式转换

例如,name 字段为 CHAR 格式,但是查询条件是 INT,查询时就会被隐式转换,如下所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE name = 666;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
  • 显示类型转换
mysql> EXPLAIN SELECT * FROM t_employee WHERE CONVERT(id, CHAR) = "10";
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

OR 引起的索引失效

查询条件使用 OR 关键字,其中一个字段没有创建索引,则会导致整个查询语句索引失效

例如,对于如下查询语句 id 字段为主键,name 不是索引:

mysql> EXPLAIN SELECT * FROM t_employee WHERE id = 10 OR name != "john snow";
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | PRIMARY,id    | NULL | NULL    | NULL |    4 |    81.25 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

对于上述查询语句,如果单独使用 username 字段作为条件很显然是全表扫描,既然已经进行了全表扫描了,前面id的条件再走一次索引反而是浪费了。

负向查询导致索引失效

对于 != 负向查询肯定不能命中索引,如下语句所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE name != "john snow";
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    75.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

对于其他的负向查询,如:BETWEENINNOT IN><NOT LIKE 等负向查询条件,查询语句是否能命中索引,会受到结果集的范围影响,如果结果集的数量较大,优化器评估全表扫描的效率更高,即使查询条件所在的列有创建索引,优化器也会选择全表扫描。

索引字段使用 IS NOT NULL 导致失效

查询条件使用 IS NULL 时,正常走索引,使用 IS NOT NULL 时,不走索引,如下所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE id IS NOT NULL;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

两列数据做比较会导致索引失效

两列数据做比较,即便两列都创建了索引,索引也会失效,如下所示:

mysql> EXPLAIN SELECT * FROM t_employee WHERE id < entity_id;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   13 |    33.33 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

标签:索引,key,MySQL,employee,失效,+----+-------------+------------+------------+------+--
From: https://www.cnblogs.com/larry1024/p/17275813.html

相关文章

  • CentOS6.4邮件配置一: postfix + dovecot + mysql + postfixadmin + Roundcubemail
    参考文章:----------------------------[size=large][color=red]可以考虑:[/color][/size]Posty——Postfix和Dovecot的管理工具[url][/url]Posty是一款基于Web的Postfix&Dovecot管理工具,功能模块包括:API、CLI和WebUI。基于Centos6.2X64系......
  • mysql 递归查询示例
    WITHRECURSIVEsubordinatesAS(SELECT*FROMsys_deptWHEREdept_id=1--这里以员工ID为1为例UNIONALLSELECTe.*FROMsys_depteINNERJOINsubordinatessONe.dept_id=s.parent_id)SELECT*FROMsubordinates;   ......
  • 访问前台页面${pageContext.request.contextPath}/el表达式失效问题解决
    最近在做项目整合这个问题,然后在项目整合的时候,遇到了好多问题,这是其中一个,在此留作记录吧,虽然关键点不是我处理好的。访问前端页面,我先描述一下具体出现的现象:我访问前端jsp页面的时候,jquery文件,js,css样式等都会失效,也就是没有引入到jsp页面当中。查看浏览器console的时候,发现${pa......
  • MySQL数据库的DML语法及使用举例
    本文列举数据库的操纵语言的语法及实际使用,以班级表作为举例:班级表:classroom点击查看创建班级表sqlcreatetableclassroom( cidintPRIMARYKEYauto_increment, cnamevarchar(20), desvarchar(50));一、插入数据语法:insertinto表名[(字段名….)]values(值….......
  • MySQL Node.js mysql 事务
    MySQLNode.jsmysql事务在MySQL数据库中,事务(transaction)是一组原子性操作,要么全部执行成功,要么全部回滚回去。在多用户并发环境中,事务可以保护数据的一致性和完整性。MySQL提供了ACID属性,并且支持事务。Node.js中,可以通过使用mysql模块的连接来实现事务。什么是事务在MySQL数......
  • Mysql命令整理
    整理一下,时常用到,不定期更新:(1)连接数据库:/local/mysql/bin./mysql--port=3301-uroot-p123456--protocol=tcp(2)创建数据库:createdatabasedbname;(3)切换数据库:use dbname ;(4)赋予权限:GRANTALLONdbname.*TO......
  • 公司某产品MySql分布式架构总结
    这个是目前公司某产品Server端MySql分布式架构总结(内容总结自wiki),该产品同时使用了Mysql和MongoDB。本篇Blog只做Mysql分布式架构的介绍。----------------------------------------------------一、共4台Linux服务器A\B\C\DAmasterwithslaveBC......
  • MySQL性能优化之 - 单表查询+代码层拼接 VS 表连接查询
    单表查询+代码端拼接的优势记得当初单位派我去阿里交流学习时,人家就说,在阿里,95%以上的查询都是单表查询,虽然我们都知道单表查询更加符合MySql底层的算法逻辑,但是单表查询+代码端拼接的优势究竟是什么,它为什么互联网企业都会使用单表查询呢?归纳而言大体分以下几点:1.激活代码端和......
  • Mysql主从复制原理
     本文总结自网上关于Mysql复制原理的一些文章。----------------------------------------------------------1、Mysql复制是一个异步的复制,从masterinstance到slaveinstance,实现整个复制操作主要使用3个进程完成。其中2个进程是Slave的Sql进程和IO进......
  • MYSQL单列索引和组合索引的对比分析
    单列索引:即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引:即一个索包含多个列。怎么选择:如果查询where条件只有一个,完全可以用单列索引,这样的查询速度较快,索引也比较瘦身。如果业务场景是需要经常查询多个组合列,不要试图分别基于单个列建立多个单......