MySQL的结构
- 连接器: 身份认证和权限相关(登录MYsql的时候)
- 查询缓存:执行查询语句的时候,会先查询缓存(MYSQL8.0后移除,因为这个功能不实用)
- 分析器:没有命中缓存的话,SQL语句就会经过分析器,主要是看SQL语句要干嘛,再检查SQL语句是否正确
- 优化器: 按照MYSQL认为的最优方案去执行
- 执行器: 执行语句,然后从存储引擎返回数据。执行语句之前会判断是否有权限,如果没有权限的话,会报错
- 插件式存储引擎:主要负责数据的存储和读取,采用的是插件式架构。
一条SQL语句在MySQL执行的流程
- 通过权限校验之后,如果执行查询语句,就会查询缓存,(MYSQL8.0后移除), 没有命中缓存,SQL就会经过分析器,查看SQL语句要干嘛,再检查SQL语句是否正确。通过后到达优化器,MYSQL会按照最优的方案去执行,最后执行器执行语句,从存储引擎返回数据。、
MySql数据库引擎有哪些(区别从行级锁、外键、事务、数据库异常崩溃后安全恢复,MVCC等方面。)
- MYISAM: 全表锁
- 优势:执行速度快,占用空间小;索引文件和数据时分离的
- 缺点: 不支持事务,不支持外键,并发性能差
- 业务:多适用于主要依赖 Select, Insert的业务中
- InnoDB:行级锁(MVCC,行级锁的升级)
- 优势:支持事务,具有提交回滚功能,默认使用REPEATABLE-READ(可重读)隔离级别,解决幻读的问题,支持外键,自动增长列,并发能力强, 支持数据库异常崩溃后安全恢复,这个过程依赖redo log; 数据文件本身就是索引文件,表数据文件本身按照B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。
- 缺点:执行速度相对于MYISAM较差一点,占用空间是MYISAM的2.5倍,但并发时性能高
- 业务:相对于更适合业务复杂的场景,比如银行转账,崩溃时能够回滚
- 如何使用命令查看:
- 查看mysql现在提供的存储引擎: show engines;
- 查看mysql当前默认的存储引擎: show variables like '%storage_engine%'
MySQL事务:
- 事务或数据库事务:在一次事务中,所有动作要么全部执行,要么都不执行。
ACID
- Atomic 原子性:事务是执行的最小单位,不可分割,要么都执行,要么都不执行。
- Consistency 一致性:执行事务前后,数据保持一致。
- Isloation 隔离性:一个事务执行不会被其他事务所干扰,并发执行的事务数据库是独立的。
- Duration 持久性:一次事务之后,对数据库的操作是持久的,就是发生故障也不会对其有任何影响。
并发事务带来了什么影响? 幻读和不可重复度的区别?
-
脏读:读到还未提交的数据
-
幻读: 在一个事务中多次执行同一查询时,由于其他事务的插入操作,导致多次的结果集不一致。
-
不可重复读:在一个事务中多次执行同一查询时,由于其他事务修改,导致结果即不一致。
-
不可重复读的重点是内容修改和记录减少,比如多次读取一条数据时发现内容被修改
-
幻读的重点是记录的行数。
-
幻读是不可重复读的一种特殊情况。
- 执行
delete和update操作的时候,可以直接对记录加锁,保证事务安全。而执行insert操作的时候,由于记录锁(Record Lock)只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁(Gap Lock)。也就是说执行insert操作的时候需要依赖 Next-Key Lock(Record Lock+Gap Lock) 进行加锁来保证不出现幻读
- 执行
事务的隔离级别:
- 读未提交:读到别人还没有提交的数据,会导致脏读,幻读,不可重复
- 读已提交:只能读到别人已经提交的数据,解决脏读,但是会引起幻读,不可重复读
- 可重复读:在一个事务中的多次查询中,最后得到的结果都是一致的。解决幻读和不可重复度。使用MVCC,读的时候会拷贝一个副本。
- 串行化:锁表执行事务,可以解决所有并发问题,但效率低下。
默认的事务隔离级别是什么? 能解决幻读吗?
- 默认的事务隔离级别: 可重复读
- 能解决幻读:
- 快照读:由MVCC保证不出现幻读
- 当前读:通过next-key-lock 保证不出现幻读,通过行锁和间隙锁来保证,行锁只能锁住已存在的行,无法避免新增记录,所以需要间隙锁。
什么是MVCC ? 有什么用? 原理是什么?
-
MVCC:多版本并发控制, 用于保持多个并发事务执行时数据的一致性和隔离性。
-
隔离级别中可重复读使用MVCC保证不出现幻读。
-
MVCC通过创建多个版本和读取快照实现并发控制。读操作,使用旧版本数据快照。写操作,使用创建新版本,并确保原始版本仍可用。这样不同事务在一定程度并发执行,而不会互相干扰,从而提高数据库的并发性能和数据一致性。
-
聚簇索引记录中有两个必要的隐藏列:
trx_id:用来存储每次对某条聚簇索引记录进行修改的时候的事务id。
roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。
这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。
(注意插入操作的undo日志没有这个属性,因为它没有老版本)
已提交读和可重复读的区别就在于它们生成ReadView的策略不同。
开始事务时创建ReadView,ReadView维护当前活动的事务id,即未提交的事务id,排序生成一个数组。
访问数据,获取数据中的事务id,对比ReadView:
如果在ReadView的左边(比ReadView都小),可以访问(在左边意味着该事务已经提交)
如果在ReadView的右边(比ReadView都大)或者就在ReadView中,不可以访问,获取roll_pointer,取上一版本重新对比(在右边意味着,该事务在ReadView生成之后出现,在ReadView中意味着该事务还未提交)
已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。
这就是Mysql的MVCC,通过版本链,实现多版本,可并发读-写,写-读。通过ReadView生成策略的不同实现不同的隔离级别
-
表级锁和行级锁有什么区别?
- 表级锁:MySQL中较大粒度的锁,是针对非索引字段加的锁,是对整张表操作进行加锁,虽然资源消耗少,加锁快,不会出现死锁,但是容易造成锁冲突。MyIsAM和Innodb的存储引擎都支持表锁。
- 行级锁:MySQL中最小粒度的锁,是针对索引字段加的锁,是对操作的行进行加锁,行级锁能大大降低锁冲突,粒度最小,但是加锁开销大,加锁慢,容易造成死锁。
行级锁有什么使用的注意事项?
- 行级锁是针对索引字段进行加锁,如果在使用update、delete操作中where没有命中索引或者索引失效,就会导致扫描全表,并对所有的行进行加锁。
共享锁和排他锁:
- 共享锁:s锁,是读锁,事务在读取数据中获取锁,允许多个读取事务同时获取(锁兼容)
- 排他锁:x锁,是写锁/独占锁,每次只能有一个进行加锁,后面的只能等待释放。一个事务修改记录时获取到锁,不允许多个事务同时获取。
- 共享锁与共享锁能兼容,排他锁与其他锁都不兼容。
- 不论是表级锁和行级锁都存在共享锁和排他锁。
意向锁:
-
判断是否对某个表使用表锁,意向锁是表锁。
-
意向共享锁,IS锁:事务有意向对某些记录加 共享锁,加锁前先要获取到意向共享锁IS.
-
意向排他锁,IX锁:事务有意向对某些记录加 排他锁,加锁前先要获取到意向排他锁IX.
-
意向共享锁、意向排他锁都是兼容的
-
只有意向共享锁和表级共享锁是兼容的,其他都不兼容。
Innodb有哪几种行锁:
- 记录锁Record Lock: 属于某行记录上的锁
- 间隙锁Gap Lock:锁定一个范围,不包括自身
- 临键锁Next-key Lock: Recorde Lock + Gap Lock, 锁定一个范围,并包含自身。用来解决幻读问题(插入)。记录锁只能锁住当前这行的数据不被篡改,需要间隙锁来保证无法插入。
- Innodb默认的隔离级别为 REPEATABLE-READ 可重复读, 行锁默认为临键锁Next-key Lock。如果当前操作的索引是唯一索引或主键,Innodb会优化为Record Lock,只会索引本身加锁,而不是范围。
索引是什么?有什么作用?优缺点?
- 索引可以看作是一种快速查找和检索数据的数据结构,或者排序好的数据结构。索引相当于书的目录。
- 优点:索引可以大大加快检索数据的速度,(减少检索数据的数据量),减少IO次数,通过创建唯一索引,来保证每行数据的唯一性。
- 缺点:创建索引和维护索引会耗费很多时间,当对数据进行增删改时,如果有索引,还需要对索引动态修改,增加了SQL执行的时间。 而且索引会使用物理文件存储,会耗费一定空间。
索引底层的数据结构?
-
排除其他选型的原因:
- Hash,是由于hash冲突,通过链表+红黑树来解决,但是MySQL没有采用是因为不能顺序查询和范围查询
- 二叉树:容易不平衡,相当于遍历查询
- AVL平衡树:通过旋转进行自平衡,但是会频繁的自旋来保持平衡,会有较大的计算消耗,影响数据库写操作的性能。
- 红黑树:与AVL不同,它是追求一个大致的平衡,所以,红黑树的高度可能会比较高,查询的次数会比较多,会增加磁盘Io的次数,降低查询效率。
- B树:每个节点都存放key索引和data数据,而且每个叶子节点都是独立的。 范围查找时,需要先找到下限,然后中序遍历,直到找到上限
-
B+Tree: 只有叶子节点才会存放key索引和data数据,内节点只有索引key, 并且每个叶子节点也有引用链指向相邻的叶子节点。检索数据时,每次都是从根节点查询到叶子节点。范围查询时,只需要遍历链表即可。
-
MYISAM采用非聚簇索引(data存储地址值,去查找文件), Innodb采用聚簇索引(data存储数据)。
B树和B+树的区别?
- 存储:B树的所有节点既存放键值也存放数据; B+树只有叶子节点能存放键值和数据,其他节点只存放键值
- 叶子节点: B树的叶子节点都是独立的; B+树的叶子节点有一条引用链指向它相邻的叶子节点,构成链表
- 检索:B树的检索过程,相当于在范围内的每个节点的关键字进行二分查找,可能没有到达叶子节点就检索到了数据; B+树的检索过程就比较稳定,都是从根节点到叶子节点
- 范围查找: B树的范围查找,只能是先找到下限,再通过B树的中序遍历,直到找到上限;而B+树只需要遍历链表即可。
- B+树相比于B树,IO次数更少,更适合范围查找,查找效率更稳定。
索引的划分
-
按照底层存储方式划分:
- 聚簇索引
- 非聚簇索引
-
按照应用的维度来划分:
- 主键索引
- 普通索引:
- 唯一索引:
- 覆盖索引:
- 联合索引:
- 全文索引:对文本的内容进行分词,进行搜索。目前只有
CHAR、VARCHAR、TEXT列上可以创建全文索引。一般不会使用,效率较低,通常使用搜索引擎如 ElasticSearch 代替。 - 前缀索引:对文本的前几个字符创建索引,相比普通索引建立的数据更小,因为只取前几个字符。
主键索引和二级索引
-
主键索引:数据表的主键列使用的索引就是主键索引。
- 主键:唯一、不为null,一个数据表只有一个主键。
- 如果数据表未指定主键索引,innodb会根据数据列查看是否有唯一且不为null的列,作为主键索引,如果没有找到,最自动创建一个6byte的自增索引。
-
二级索引:二级索引的叶子节点数据存储的是主键的值,也就是可以通过二级索引找到主键的位置,又称辅助索引/非主键索引
- 唯一索引:主要是一种约束,使用的数据列不允许出现重复,可以为NULL,一张表允许创建多个唯一索引。主要是为了唯一性,而不是提升查询效率。
- 普通索引:主要是为了提升查询效率,一个表允许创建多个普通索引。并且允许数据重复和为null.
- 前缀索引:只适用于字符型的数据,会根据数据的前面几个字符进行查询
- 全文索引:主要是为了检索大文本数据中的关键字信息,目前搜索引擎数据库使用的一种技术。MySQL5.6之前只有MyISAM支持,5.6之后只有Innodb支持。
聚簇索引和非聚簇索引
- 聚簇索引:索引和数据一起存放的索引,主键索引就是聚簇索引。
- 优点:
- 查找速度快:找到索引,就能直接得到数据,减少了一次Io的次数
- 排序查找和范围查找比较快
- 缺点:
- 依赖主键的顺序性,如果无法排序,插入和查找的速度就会比较慢
- 更新代价大:索引列更新修改数据时,索引对应的索引也要跟着一起修改。所以对于主键索引列,数据一般都是不可被修改的。
- 优点:
- 非聚簇索引:索引单独存放,data数据存放的是地址值 或 是二级索引的叶子节点存储的是主键, 是会通过主键再去回表查询数据。
- 优点:
- 更新代价比聚簇索引的代价小,非聚簇索引叶子节点不存放数据
- 缺点:
- 依赖有序数据:无序的会查找慢
- 可能会二次回表:可能会根据data的地址值查找到数据文件进行查询,或者根据主键进行回表查询。
- 优点:
回表
- 在innodb存储引擎中,非主键索引的叶子节点包含的值是主键值时,意味着,进行此非主键查询时,数据库会先找到对应的主键值,再根据主键索引查找定位对应的行数据,这种情况叫做回表。
覆盖索引:
- 覆盖索引:一个索引包含所有要查询的字段,直接根据索引就能查到数据,就无需回表查询
联合索引:
- 就是使用表中多个字段创建的索引,也叫组合索引或复合索引。
Select 的七大子句
select 内容(字段名、函数、表达式) ① from 表名 ② on 设置关联条件(去除笛卡尔积) ③ where 设置筛选条件 ④ group by 字段名 ⑤ having 筛选条件(分组之后进行操作) ⑥ order by 排序 ⑦ limit 分页
三大范式
- 第一范式:保证每个列的原子性,即不可拆分。
- 第二范式:保证每个列直接依赖与主键(在第一范式的基础上,消除非主属性对于主键的部分依赖)
- 第三范式:非主键字段之间不能出现传递依赖的关系
- 作用: 使得表结构清晰,减少数据冗余(重复),提高查询和存储效率。
优化口诀:避免索引失效
-
【select * 前提下】 全值匹配我最爱,最左前缀要遵循 带头大哥不能死,中间兄弟不能断 索引列上少计算,范围之后全失效 LIKE百分写最右,覆盖索引不写* 不等空值还有OR,索引影响要注意 VAR引号不可丢,SQL优化有诀窍
-
最佳左前缀法则: 如果索引了多列,要遵循最左前缀法则:查询从索引的最左前列开始并且不跳过索引中的列。
-
不在索引列做任何操作(计算、函数、(自动Or手动)类型转换),会导致索引失效而转向全表扫描
-
存储引擎不能使用索引中范围条件右边的列
-
尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少 select *
-
注意null/not null对索引的可能影响
-
like以通配符开头('%abc...')mysql索引失效会变成全表扫描的操作、
-
字符串不加单引号索引失效
-
mysql 在使用不等于(!= 或者 <>)的时候有时候无法使用索引会导致全表扫描
-
少用or,用它来连接时会索引失效
-
解决上述索引失效的问题:覆盖索引:select 到 from 查询到的列 <= 使用的索引列 + 主键
-
正确使用索引的建议:
-
选择合适的字段创建索引:
- 不为NULL的:数据库比较难解析NULL, 如果要频繁查询,又无法避免可以使用0,1,true,false这些短值进行代替。
- 被频查询的字段
- 被where条件查询的字段
- 频繁需要排序的字段
- 频繁需要被连接的字段:就是多表联合查询时,对于频繁作为连接的字段,增加索引提高查询效率。
-
被频繁更新的字段,慎重选择创建索引:因为维护索引的成本不小,如果当前查询次数少,更新频繁的就不要创建索引了。
-
限制每张表的索引数量: 不超过5个,mysql优化器会选择合适的索引来生成执行计划,如果可以查询的索引过度,会影响生成执行计划的时间。
-
尽可能考虑使用联合索引而不是单列索引:因为每个索引都是需要空间的,选择联合索引,节省了空间,还增加修改索引的效率。
-
删除长期未使用的索引
-
避免索引失效的场景:
- select *,并且where指向的范围过大
- 使用联合索引时,查询条件没有遵从最左前缀原则
- 索引列进行了计算、函数、类型转换等操作
- 以 % 开头的LIKE查询比如
LIKE %abc - 查询中使用OR,如果OR的前后有个没有使用到索引列,被涉及索引就都不会被使用了。
- IN(not in)使用的范围过大时,会导致全表扫描: in 在结果集 大于 30%的时候索引失效
- order by
关联查询优化
- 保证被驱动表的join字段被索引
- left join时,选择小表作为驱动表,大表作为被驱动表
- inner join时,mysql会自己帮你把小结果集的表选为驱动表
- 子查询尽量不要放在被驱动表,有可能使用不到索引
- 能够直接多表关联的尽量直接多表关联,不用子查询。
排序分组优化
- Order by关键字优化:
- order by 子句,尽量使用Index方式排序,避免使用FileSort方式排序
- 尽可能在索引列上完成排序操作,遵循索引键的最佳左前缀
- group by关键字优化:
- group by实质是先排序后进行分组,遵照索引键的最佳左前缀
- where 高于 having, 能写在where限定的条件就不要去having限定了
- group by 使用的索引原则几乎与order by 一致,唯一区别是 group by 即使没有过滤条件用到索引,也可以直接使用索引。
MySQL中常见的日志
- 错误日志(err.log):对MySQL的启动、运行、关闭进行记录。
- 二进制日志(binlog):主要记录修改数据库数据的SQL语句。
- 一般查询日志:已建立的客户端向数据库发送的查询sql语句进行记录,因为SQL量大,默认不开启,不推荐开启。
- 慢查询日志(slow query log): 记录执行时间超过 long_query_time 时间的查询。解决慢查询时会用到
- 事务日志(redo log和 undolog): redo log是重做日志,undo log是回滚日志
- 中继日志(relay log): relay log是复制过程中产生的日志,大多数与bin log差不多。主要针对主从复制的从库。
- DDL(metadata log): DDL执行元数据的操作。
慢查询日志的作用?
- 慢查询: 记录所有执行超过long_query_time时间的查询(默认是10是,一般设置为1s),通常是解决SQL慢查询问题时用到。
- 可以使用
show variables like 'slow_query_log';来查看慢查询日志是否开启,默认关闭 - 实际项目中,慢查询日志会比较大,比较难分析,推荐使用Mysql官方慢查询分析工具 mysqldumpslow MySQL :: MySQL 5.7 Reference Manual :: 4.6.8 mysqldumpslow — Summarize Slow Query Log Files
- 然后使用explain分析工具分析慢查询语句。
binlog主要记录了什么?又什么作用?
-
记录了对所有数据修改的所有操作,(DDL和DML),包括表相关的操作(CREATE\DROP\ALTER TABLE等),数据相关的操作(insert\update\delete), 而不会记录查询且不会修改数据的操作(select show)
-
binlog日志的格式:statment的日志文件比row小,但是准确性要差一些
- statement:记录每个对数据修改的语句sql,比如(update delete insert)
- row: 记录每行具体的变更事件
- Mixed: statement和row的混合模式,默认使用statement, 出现特殊情况,使用row进行记录。
- 使用
show variables like '%binlog_format%'查询使用的格式
-
作用:主要是主从复制,主备,主主,主从,都依赖binlog来同步数据,保持数据的一致性
- 主从复制的原理:
- 主库将数据写入到binlog中
- 从库连接主库
- 从库创建IO线程向主库请求binlog日志
- 主库会新建一个binlog dump线程发送,向从库的IO线程接收
- 从库将接收到的binlog存储到relay log中
- 从库完成数据库同步操作(将relay log中的sql重新执行)
- 主从复制的原理:
-
作用二:用于误删除恢复,当误删除数据时,可以使用binlog进行重新恢复。
redolog是如何保证事务的持久性的?
- Innodb是以数据页的数据结构来存储数据的,一般是从Buufer Pool(缓存池)中读取,如果Buffer Pool中没有,会从数据库中读取,缓存到Buffer Pool中,基本都是操作Buffer Pool中的页数据,最后写入到磁盘中。虽然加快了IO的读取,但是如果mysql出现宕机,数据就可能丢失,这时候就会破坏事务的持久性,redolog发挥作用了
- redolog会记录页的修改,事务提交之后,redolog会根据刷盘策略,持久化到磁盘中,即使mysql宕机了,重启也能恢复未写入的数据,保证事务的持久性。
- 刷盘策略:一定情况会自动刷盘,事务提交(1)、logbuffer空间不足时,定时任务、定期执行检查点操作
- 0:表示每次事务提交时不进行刷盘
- 1:表示每次事务提交时进行刷盘
- 2:表示每次事务提交时,将redolog写入page Cache(文件系统缓存中)
页修改之后为什么不直接刷盘呢?
- 性能非常差,innodb页的大小一般为16kb, 是磁盘和内存交互的基本单位,如果只是修改几个字节的数据,一次刷盘操作也需要将整个页都刷新到磁盘中,并且修改的这些页可能是不连续的,也就是随机IO
- 采用redo log就可以避免这种操作,redolog刷盘性能高,redolog的写入属于顺序IO, 一行redolog只占几十字节。
binlog和redolog之间的区别?
- 用途:
- binlog:存储数据变化的语句,主要用于主从复制和 数据库还原,属于数据级别的恢复。
- redolog: 保证事务的持久性,是事务级别的恢复。
- 引擎特有:
- redolog: innodb引擎特有(数据页)
- binlog:所有引擎都有
- 物理还是逻辑日志:
- redolog: 是物理日志,存储页的变化记录
- binlog: 是逻辑日志,记录数据变化的日志
- 写入方式和大小:
- binlog: 追加的方式写入,没有大小限制
- redolog: 采用循环的方式写入,大小固定,写到结尾,会回到开头循环写入。
undolog是如何保证事务的原子性的?
- undolog: 每个事务对数据的修改都会记录到undolog中,当事务执行出错或者需要执行回滚时,就是根据undolog将数据恢复到事务执行前的状态。
- undolog是逻辑日志,记录SQL语句。
8.SQL执行的顺序(一般情况下)
- 手写:
SELECT DISTINCT
<select_list>
FORM
<left_table> <jion type> JOIN <right_table> ON <join_condition>
WHERE
<where_condition>
GROUP BY
<group_by_list>
HAVING
<having_condition>
ORDER BY
<order_by_condition>
LIMIT <limit_number>
- 机器读的顺序:
FORM <left_table> ON <join_conditon> <join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT DISTINCT
<select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>
9.7中join图
- 1 A、B两表共有
- select * from tbl_emp a inner join tbl_dept b on a.deptId = b.id;
- 2 A、B量表共有+A独有
- select * from tbl_emp a left join tal_dept b on a.deptId = b.id;
- 3 A、B两表共有+B独有
- select * from tbl_emp a right join tbl_dept b on a.deptId = b.id;
- 4 A的独有
- select * from tbl_emp a left join tbl_dept b on a.deptId=b.id where b.id is null;
- 5 B的独有
- select * from tbl_emp a right join tbl_dept b on a.deptId=b.id where a.deptId is null;
- 6.AB全由
- select * from tbl_emp a left join tbl_dept b on a.deptId=b.id union select * from tbl_emp a right join tbl_dept b on a.deptId=b.id
- 7.A的独有 + B的独有
- select * from tbl_emp a left join tbl_dept b on a.deptId=b.id where b.id is null union select * from tbl_emp a right join tbl_dept b on a.deptId=b.id where a.deptId is null;
10. Innodb的行锁到底锁住了什么?
- InnoDB的行锁,是通过锁住索引来实现的,如果加锁查询的时候没有使用到索引,会将整个聚簇索引都锁住,相当于锁表。
- 命中索引锁行,没有命中锁表,问题会扩大化。
11. Explan
-
是什么:使用EXPLAN关键字可以模拟优化器执行SQL查询语句,从而直到MySQL是如何处理你的SQL语句。分析你的查询语句或是表结构的性能瓶颈。
-
使用: EXPLAN + SQL语句
- 执行计划包含的信息:
- 执行计划包含的信息:
-
作用:
- 表的读取顺序
- 数据读取操作的操作类型
- 那些索引可以使用
- 那些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
-
EXPLAN的各个字段的解释:
-
id: select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
- id相同,执行顺序由上至下
- id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
- id相同不同,同时存在:id如果相同可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
- 注意:id号每个号码,表示一趟独立的查询,一个SQL的查询趟数越少越好。
-
select_type: 查询的类型,主要用于区别普通查询、联合查询、子查询等复杂查询
- SIMPLE:简单的select查询,查询中不包含子查询和UNION
- PRIMARY: 若查询语句中包含复杂的子查询,那么最外层的查询被标记为PRIMARY
- SUBQUERY: 在SELECT或WHERE中包含了子查询。
- DERIVED: 在FROM 列表中包含的子查询被标记为DERIVED(衍生) MySQl会递归执行这些子查询,把结果放在临时表里
- UNION: 若第二个SELECT 出现在UNION之后,则被标记为UNION; 若 UNION 包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
- UNION: 从UNION表获取结果的SELECT
-
table: 显示这一行的数据是关于哪张表的
-
partions: 代表分区表中的命中情况,如果没有进行过分操作的非分区表,该项为null
-
type: 显示的是访问类型,是较为重要的一个指标。
- 结果值从最好到最坏依次是: system > const < eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
- system > const >eq_ref > ref> range > index > ALL
- 一般来说,的保证查询至少达到range级别,最好能达到ref
- system:表只有一行记录(等于系统表),这是const类型的特例, 平时不会出现,这个也可以忽略不计
- const: 表示通过索引一次就找到了,const 用于比较primary key 或者 unique 索引。 因为只匹配一行数据,所以很快将主键置于where列表中, MySQL就能将该查询转换为一个常量
- eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
- ref: 非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
- range: 只检索给定范围的行,使用一个索引来选择行。 key 列显示使用了哪个索引,一般就是在你where语句中出现了 between、< 、>、 like 、in 等查询。 这种范围扫描索引扫描比全表扫描要好,因为它只需要开始索引的某一点,而结束语另一点,不用扫描全部索引
- index: FULL Index Scan, index与ALL却别为index类型只遍历索引树, 这通常比ALL快,因为索引文件通常比数据文件小。 (也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读取的)
- all: FULL Table Scan, 将遍历全表以找到匹配的行
- index_merage: 在查询过程中需要多个索引组合使用,通常出现在有 or 的关键字的sql中
- ref_or_null: 对于某个字段既需要关联条件,也需要null值得其概况下。 查询优化器会选择使用ref_or_null 连接查询
- index_subquery: 利用索引来关联子查询,不再全表扫描
- unique_subquery: 该连接类型类似于index_subquery。子查询中唯一索引。
-
possible_keys: 显示可能应用在这张表中的索引,一个或多个。 查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用
-
key: 实际使用的索引。 如果为nuLL, 则没有使用索引。 查询中若使用了覆盖索引,则该索引和查询的select字段重叠
-
key_len: 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。 葛奴据它可以判断索引的使用情况,尤其是在组合索引的时候,判断该索引有多少部分被使用到非常重要。
-
ref: 显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
-
rows: 显示MySQL认为它执行查询时必须检查的行数,值越小越好
-
filtered: 这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意时百分比,不是具体记录数。
-
Extra: 包含不适合在其他列中显示但十分重要的额外信息 -Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内索引顺序进行读取。 MySQL中无法利用索引完成的排序操作称为“文件排序”
-
Using temporary: 使用临时表保存中间结果,MySQL在对查询结果排序时使用临时表,常见于排序order by 和分组查询 group by
-
USING index: 表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效果不错! 如果同时出现using where, 表明索引被用来执行索引键值的查找; 如果没有同时出现using where,表明索引用来读取数据非执行查找动作。
-
USING where: 表明使用了where过滤。
-
-