MySQL索引优化一

article/2025/11/7 4:52:00

MySQL索引

索引是什么

  • 索引是一种排好序数据结构,目的是提高查找效率
  • 一般来说,索引本身也占内存,因此索引以文件的形式存储在磁盘上
  • 平常我们所说的索引一般都是B+Tree。当然还有hash索引等等

索引优劣势

  • 优势:提高检索效率,降低数据库IO成本。由于数据都已经排好序,降低了排序的成本,降低CPU的消耗
  • 劣势:索引也要占用空间、在INSERT/DELETE/UPDATE的时候需要同步更新索引

索引分类

  • 单值索引:索引只有一个列
  • 唯一索引:索引列的值必须唯一,允许空值
  • 复合索引:索引包含多个列

索引结构

  • 详见MySQL索引结构介绍

建立索引情形

  • 频繁查询的字段
  • 与其它表关联的字段需要创建索引
  • 频繁更新的字段不适合创建索引(更新数据的时候需要更新索引)
  • 查询中存在排序的字段,排序若通过索引去访问则大大提高访问的效率
  • 查询中统计和分组的字段,因为group by之前需要先排序

性能分析(MySQL Query Optimizer)

  • Explain是什么?可以模拟查询sql语句,可以知道MySql是如何执行SQL,分析语句的性能瓶颈
  • Explain能够干什么?
    • 表的读取顺序
    • 数据读取的操作类型
    • 哪些索引可以使用
    • 哪些索引实际被使用
    • 表之间的引用
    • 每张表有多少行被优化器查询
  • 使用方式
-- 1、简单使用
explain select * from emp;-- 2、explain扩展使用,可查看优化执行情况
explain extended select * from emp;
show warnings ;-- 3、结合分区使用
explain partitions select * from emp;
  • 执行计划包含的内容(简单使用):
    执行计划字段
  • id:表示查询执行顺序,代表select的个数,分为三种情况①id相同,从上往下执行,②id不同,id越大优先级越高,越先执行id为null最后执行(画外音:union查询id为null)
  • select_type:查询的类型主要用于区分普通查询、联合查询、子查询,类型有
    • SIMPLE:简单查询。查询不包含子查询和union
    • PRIMARY:复杂查询中的最外层查询
    • SUBQUERY:在select中的子查询,不在from中
    • DERIVED:在from中的子查询,数据放在临时表中
    • UNIONUNION RESULT:存在union查询,union result获取结果
  • 下面列表展示了上面几种查询类型,可以看出在select_typeunion result的时候id是空的
explain select (select name from dept where id = a.dept_id) deptName from (select * from emp) a union  select 1;

查询类型

  • table:表示访问的是哪个表,当 from 子句中有子查询时,table列是 格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询,UNION RESULT 的 table 列的值为<union1,2>,1和2表示参与 union 的 select 行id
  • type:访问数据类型,从最优到最差为system > const > eq_ref > ref > range > index > ALL
  • system 表中只有一条数据,是const的特例,一般的情况下不会出现
  • const 查询条件为primary key或者unique key的时候匹配一条数据
  • eq_ref primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录,这个是const之后最好的链接类型了
explain select * from emp a left join dept d on a.dept_id = d.id;

  • ref 相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。ref可以出现在简单的非唯一索引查询和联合的非唯一索引查询
  • range 范围扫描通常出现在 in(), between ,> ,<, >= ,<=等操作中。使用一个索引来检索给定范围的行
  • index 扫描全表索引,这通常比ALL快一些。(index是从索引中读取的,而all是从硬盘中读取)
-- index
explain select job_id from emp ;

  • all 即全表扫描,意味着MySQL需要从头到尾去查找所需要的行。
  • possible_keys :这一列显示查询可能使用哪些索引来查找。 explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,MySQL认为索引对此查询帮助不大,选择了全表查询。如果该列为null,可以创建索引来提高检索效率
  • key:实际使用的索引。如果为null,则表示没有使用索引。如果使用覆盖索引,则和extra中的using index一致
  • key_len:实际使用索引的字节数。(画外音:长度后面介绍,跟编码有关系)注意:索引最大长度是768字节,超过长度的索引会变为最左前缀。实际使用的时候需要尽可能的减少索引的长度,提高左边的识别度。因为索引占空间
  • ref:这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名
  • rows:这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数
  • extra:查询的额外信息,类型以及描述如下表:
类型描述
Using index查询列被索引覆盖,避免回表查询,是查询性能好的表现
Using where查询列被索引覆盖,需要回表查询
Using where Using index查询的列被索引覆盖,并且where筛选条件是索引列之一但是不是索引的前导列,无法通过索引查找到数据
Null查询的列未被索引覆盖,并且where筛选条件是索引的前导列,意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是纯粹地用到了索引,也不是完全没用到索引
Using index condition查询列不完全被索引覆盖,where条件是前导列的一个范围
Using temporary使用临时表来处理查询,这个时候需要优化查询
Using filesort对结果使用一个外部索引排序,而不是按索引次序从表里读取行,这个时候需要优化查询
mysql> -- extra
mysql> -- using index
mysql> explain select job_id from emp where job_id = 1;
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys   | key             | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | idx_job_id_name | idx_job_id_name | 9       | const |    3 | Using index |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
1 row in set (0.00 sec)mysql> -- using where
mysql> explain select * from emp where name = '1';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |    8 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)mysql> -- Using where Using index
mysql> explain select job_id,name from emp where name = 'frank';
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | emp   | index | NULL          | idx_job_id_name | 139     | NULL |    8 | Using where; Using index |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)mysql> -- Null
mysql> explain select * from emp where job_id = 1;
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys   | key             | key_len | ref   | rows | Extra |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------+
|  1 | SIMPLE      | emp   | ref  | idx_job_id_name | idx_job_id_name | 9       | const |    3 | NULL  |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------+
1 row in set (0.00 sec)mysql> -- Using index condition
mysql> explain select * from emp where job_id > 100;
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
|  1 | SIMPLE      | emp   | range | idx_job_id_name | idx_job_id_name | 9       | NULL |    1 | Using index condition |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)mysql> -- Using temporary
mysql> explain select distinct name from emp ;
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+------------------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                        |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+------------------------------+
|  1 | SIMPLE      | emp   | index | idx_job_id_name | idx_job_id_name | 139     | NULL |    8 | Using index; Using temporary |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+------------------------------+
1 row in set (0.00 sec)mysql> -- Using filesort
mysql> explain select name from emp order by name;
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+-----------------------------+
| id | select_type | table | type  | possible_keys | key             | key_len | ref  | rows | Extra                       |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+-----------------------------+
|  1 | SIMPLE      | emp   | index | NULL          | idx_job_id_name | 139     | NULL |    8 | Using index; Using filesort |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+-----------------------------+
1 row in set (0.00 sec)
  • 画外音:索引的前导列针对联合索引中后面的索引

索引最佳实践

  • 全值匹配我最爱
  • 最佳左前缀原则(但是skip scan例外)–带头大哥不能少,中间兄弟不能断(只能用到部分的索引)
  • 不要再索引上进行任何计算
  • 索引不能使用范围右边的列
  • 尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少select *语句
  • mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描(如果覆盖索引则可以显示出来)
  • is null,is not null 也无法使用索引
  • like以通配符开头(’%abc…’)mysql索引失效会变成全表扫描操作
  • 字符串不加单引号索引失效
  • 少用or,用它连接时很多情况下索引会失效
mysql> -- 最佳左前缀法则(job_id,name)
mysql> explain select job_id from emp where job_id = 1;
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys   | key             | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | idx_job_id_name | idx_job_id_name | 9       | const |    3 | Using index |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
1 row in set (0.00 sec)mysql> explain select job_id from emp where name = 'frank';
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | emp   | index | NULL          | idx_job_id_name | 139     | NULL |    8 | Using where; Using index |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)mysql> -- 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
mysql> explain select * from emp where job_id + 1 = 3;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |    8 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)mysql> -- 存储引擎不能使用索引中范围条件右边的列
mysql> explain select * from emp where job_id > 100 and name = 'frank';
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
|  1 | SIMPLE      | emp   | range | idx_job_id_name | idx_job_id_name | 9       | NULL |    1 | Using index condition |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)mysql> -- 尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少select *语句
mysql> explain select id, name, job_id,salary, dept_id from emp where job_id > 100;
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
|  1 | SIMPLE      | emp   | range | idx_job_id_name | idx_job_id_name | 9       | NULL |    1 | Using index condition |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)mysql> explain select job_id from emp where job_id > 100;
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | emp   | range | idx_job_id_name | idx_job_id_name | 9       | NULL |    1 | Using where; Using index |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)mysql> -- mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描(如果覆盖索引则可以显示出来)
mysql> explain select name,emp.salary from emp where job_id != 1;
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys   | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | idx_job_id_name | NULL | NULL    | NULL |    8 | Using where |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)mysql> -- is null,is not null 也无法使用索引
mysql> explain select emp.salary,job_id,name from emp where job_id is not null;
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys   | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | idx_job_id_name | NULL | NULL    | NULL |    8 | Using where |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)mysql> -- like以通配符开头('%abc...')mysql索引失效会变成全表扫描操作
mysql> explain select name from emp where name like 'frank%';
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | emp   | index | NULL          | idx_job_id_name | 139     | NULL |    8 | Using where; Using index |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
--下面两个比较简单
mysql> -- 字符串不加单引号索引失效
mysql> -- 少用or,用它连接时很多情况下索引会失效
  • 最后借用一张图来表示联合索引的最佳实践
    联合索引最佳实践

总结

  • 索引(index)跟新华字典的索引目录类似,提高了检索的效率,在实践过程中也有很多需要注意的地方。平常大家可以多多的通过执行Explain来查看执行计划,分析SQL,写出高效的SQL,当然如果只是上面的内容还不够大家在日常工作中使用的,接下来还有多篇关于MySQL优化,欢迎关注!

欢迎可以关注spring-cloud系列 openfeign hystrix,也可以关注JAVA-打怪升级系列
你的点赞和关注是我创作的最大动力,有什么不足和错误的地方欢迎留言!可以微信搜索关注【小二说码


http://chatgpt.dhexx.cn/article/Nt2ZXxht.shtml

相关文章

MYSQL索引详解和优化

索引的定义 我们在看书的时候&#xff0c;都知道有目录&#xff0c;我们可以通过目录快速的找到书中的内容&#xff0c;而书中的目录就是充当书的索引。在数据库中的索引也是一样的。 索引的定义&#xff1a; 索引是帮助存储引擎快速获取数据的一种数据结构&#xff0c;即数据…

一文彻底搞懂Mysql索引优化

专属小彩蛋&#xff1a;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff08;前言 - 床长人工智能教程&#xff09; 目录 一、索引介绍 二、性能分析 三、查询优化 四、排序优化…

MYSQL通过索引进行优化

MYSQL通过索引进行优化 一&#xff1a;什么是索引&#xff1a; 在关系数据库中&#xff0c;索引是一种与表有关的数据库结构&#xff0c;它可以使对应于表的 SQL 语句执行得更快。索引的作用相当于图书的目录&#xff0c;可以根据目录中的页码快速找到所需的内容。 对于数据…

MySQL索引优化(超详细)

Mysql索引优化 1 索引介绍 1.1 什么时MySQL的索引 ​ MySQL官方对于索引的定义:索引是帮助MySQL高效获取数据的数据结构。 ​ MySQL在存储数据之外&#xff0c;数据库系统中还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种引用(指向)表中的数据&#xff…

MySQL索引(二)索引优化方案有哪些

在上一篇文章中&#xff0c;我们介绍了MySQL中常见的索引类型以及每种索引的各自特点&#xff0c;那么这篇文章带你来与我一起看一下聚集索引与二级索引的关系&#xff0c;最后在附上常见的索引优化方案。首先我们还是看一下聚集索引和二级索引的区别 MySQL索引&#xff08;一…

【MySQL】索引优化原则

前面几篇博文谈到索引使用场景和explain命令帮助我们分析索引的执行情况&#xff0c;今天进入正题&#xff0c;来谈谈索引优化的原则。 1、全值匹配 查询语句尽量使用全值匹配。 2、左前缀原则 如果一个索引是组合索引&#xff0c;索引了多列&#xff0c;要遵循左前缀原则…

MySQL:索引优化、查询优化

一、哪些情况适合创建索引 1、字段的数值有唯一性的限制&#xff1b; 业务上具有唯一特性的字段&#xff0c;即使是组合字段&#xff0c;也必须建成唯一索引&#xff1b; 说明&#xff1a;创建唯一索引会影响添加的速度&#xff08;在添加的时候会维护索引&#xff09;&…

Mysql-索引优化

一、索引基本知识 1、索引的优点 很大程度上减少服务器扫描的数据量很大程度上避免服务器排序和临时表将随机IO变成顺序IO 2、索引的用处 使用索引列可以快速查找Where条件的行数据 mysql> explain select * from emp where empno 7469; ----------------------------…

MySQL索引优化总结

前言&#xff1a;相信大家都知道索引可以大大提高MySQL的检索速度&#xff0c;但是真正在平时工作中写SQL&#xff0c;真的会考虑到这条SQL如何能够用上索引提升执行效率&#xff1f;本篇博客详细的介绍了索引优化的20个原则&#xff0c;只要在工作中能够随时应用到&#xff0c…

【MySQL】深入理解MySQL索引优化器原理(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

mysql 索引优化

一、mysql索引建立原则 二、通过 EXPLAIN 分析 SQL 执行计划 可以知道以下内容&#xff1a; 假设现在我们使用 EXPLAIN 命令查看当前 SQL 是否使用了索引&#xff0c;先通过 SQL EXPLAIN 导出相应的执行计划如下&#xff1a; 下面对图示中的每一个字段进行一个说明&#x…

【MySQL】MySQL索引优化——从原理分析到实践对比

目录 使用TRACE分析MySQL优化 开启TRACE TRACE 结果集 ORDER BY & GROUP BY 优化 优化方式 分页优化 不同场景的优化方式 JOIN关联优化 算法介绍 优化方式 COUNT优化 优化方式 使用TRACE分析MySQL优化 某些情况下&#xff0c;MySQL是否走索引是不确定的[,,_,,…

MySQL索引常见面试题(2022版)

目录 为什么要建立索引&#xff1f; 哪些情况适合建立索引&#xff1f; 哪些情况下不适合建索引&#xff1f; 为什么索引是使用B树&#xff1f;&#xff08;重点&#xff09; 索引分为那几类&#xff1f; 什么是聚簇索引&#xff1f;&#xff08;重点&#xff09; 使用聚…

mysql数据库索引优化【建议收藏】

在我们程序员玩数据库的时候&#xff0c;经常会写sql&#xff0c;但是决定一个sql的好坏往往是效率&#xff0c;于是我们需要不断的去优化我们的sql&#xff0c;写一句让人称赞的sql是非常不容易的&#xff0c;也是需要大家有非常深厚的功底&#xff0c;所以优化路漫漫&#xf…

MySQL索引优化

MySQL索引优化 一、优化索引的方法二、优化步骤前缀索引优化覆盖索引优化主键索引最好是自增的索引最好设置为NOT NULL防止索引失效 总结 一、优化索引的方法 这里说一下几种常见优化索引的方法&#xff1a; 前缀索引优化&#xff1b; 覆盖索引优化&#xff1b; 主键索引最好是…

Android底层到上层的开发流程

安卓系统整体框架图如下&#xff1a; 简单总结如下&#xff1a; 1、在kernel层编写你的驱动程序&#xff1a;生成设备文件节点跟上一层传输数据&#xff0c;主要调用函数copy_to_user和copy_from_user&#xff0c;注意赋节点权限问题。 2、在HAL层封装对上提供的函数接口&…

【Android】Android底层开发实战

本书分为四个部分&#xff1a;第一部分为预备知识篇&#xff0c;简要介绍嵌入式系统的定义与软硬件开发以及Android开发环境的搭建。第二部分为系统结构篇&#xff0c;主要介绍Android系统的源码结构、内核与相关工具以及环境库。第三部分为驱动设计篇&#xff0c;主要介绍Andr…

我做了几年的Android应用层开发,为什么还要去学习安卓系统知识?

作为一个工作了好几年的Android应用层开发者&#xff0c;我准备在工作之余干一件事情&#xff0c;那就是学习Android系统知识&#xff0c;为什么要做这个决定呢&#xff1f; 其主要原因是想在Android应用层开发进阶 这个说起来并非易事&#xff0c;可能在很多人的认知里&…

一个Android应用层开发如何转型深入Android Framework?

作为一个工作了好几年的Android应用层开发者&#xff0c;准备在工作之余干一件事情&#xff0c;那就是分享一些Android系统知识&#xff0c;为什么决定要做这个呢&#xff0c;理由如下&#xff1a; 帮助更多人转型Android系统开发 不知何时起&#xff0c;单纯的Android应用层…

android底层开发-android基础架构

android architecture 在安卓中&#xff0c;最经典的架构就是分四层&#xff0c;分别是application、framework、libraries、kernel四层&#xff0c;通过这四层将android的整个架构都丰满起来 其架构图如下 android 系统组成 &#xff30;rocess FW: android 系统固件&#…