3、MySQL 逻辑架构简介
3.1、整体架构图
连接层
最上层是一些客户端和连接服务,包含本地 sock 通信和大多数基于客户端/服务端工具实现的类似于 tcp/ip 的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于 SSL 的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
服务层
Management Serveices & Utilities | 系统管理和控制工具 |
---|---|
SQL Interface | SQL 接口。接受用户的 SQL 命令,并且返回用户需要查询的结果。比如 select from就是调用 SQL Interface |
Parser | 解析器。 SQL 命令传递到解析器的时候会被解析器验证和解析 |
Optimizer | 查询优化器。 SQL 语句在查询之前会使用查询优化器对查询进行优化,比如有where 条件时,优化器来决定先投影还是先过滤。 |
Cache 和 Buffer | 查询缓存。如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key 缓存,权限缓存等 |
引擎层
存储引擎层,存储引擎真正的负责了 MySQL 中数据的存储和提取,服务器通过 API 与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。
存储层
数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。
3.2、存储引擎
show engines; —查看所有的数据库引擎
show variables like ‘%storage_engine%’; —查看默认的数据库引擎
MyISAM 和 InnoDB
对比项 | MyISAM | InnoDB |
---|---|---|
外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 | 行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作 |
缓存 | 只缓存索引,不缓存真实数据 | 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 |
关注点 | 读性能 | 并发写、事务、资源 |
默认使用 | N | Y |
4、索引优化分析
4.1、SQL 执行顺序
- 手写的顺序:
- 真正执行的顺序:
查询流程
- mysql 客户端通过协议与 mysql 服务器建连接,发送查询语句,先检查查询缓存,如果命中,直接返回结果,否则进行语句解析,也就是说,在解析查询之前,服务器会先访问查询缓存(query cache)——它存储 SELECT 语句以及相应的查询结果集。如果某个查询结果已经位于缓存中,服务器就不会再对查询进行解析、优化、以及执行。它仅仅将缓存中的结果返回给用户即可,这将大大提高系统的性能。
- 语法解析器和预处理:首先 mysql 通过关键字将 SQL 语句进行解析,并生成一颗对应的“解析树”。mysql 解析器将使用 mysql 语法规则验证和解析查询;预处理器则根据一些 mysql 规则进一步检查解析数是否合法。
- 查询优化器当解析树被认为是合法的了,并且由优化器将其转化成执行计划。一条查询可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。
- 然后,mysql 默认使用的 BTREE 索引,并且一个大致方向是:无论怎么折腾 sql,至少在目前来说,mysql 最多只用到表中的一个索引。
4.2、常见的 Join 查询
1、SELECT * FROM tbl_emp a LEFT JOIN tbl_dept b ON a.deptId=b.id;
2、SELECT * FROM tbl_emp a INNER JOIN tbl_dept b ON a.deptId=b.id;
3、SELECT * FROM tbl_emp a RIGHT JOIN tbl_dept b ON a.deptId=b.id;
4、SELECT * FROM tbl_emp a LEFT JOIN tbl_dept b ON a.deptId=b.id WHERE b.id IS NULL;
5、SELECT * FROM tbl_emp a RIGHT JOIN tbl_dept b ON a.deptId=b.id WHERE a.deptId IS NULL;
6、 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、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;
4.3、索引的概念
4.3.1、定义
MySQL 官方对索引的定义为:索引(Index)是帮助 MySQL 高效获取数据的数据结构。可以得到索引的本质:索引是数据结构,可以简单理解为排好序的快速查找数据结构。
4.3.2、优缺点
优势:
- 提高数据检索的效率,降低数据库的IO成本。
- 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
缺点:
- 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
- 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的。
4.4、索引的分类
4.4.1、单值索引
概念: 即一个索引只包含单个列,一个表可以有多个单列索引
1、KEY (customer_name)
2、CREATE INDEX idx_customer_name ON customer(customer_name);
4.4.2、唯一索引
概念: 索引列的值必须唯一,但允许有空值
1、UNIQUE (customer_no)
2、CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);
4.4.3、主键索引
概念: 设定为主键后数据库会自动建立索引,innodb为聚簇索引
1、PRIMARY KEY(id)
2、ALTER TABLE customer add PRIMARY KEY customer(customer_no);
删除
ALTER TABLE customer drop PRIMARY KEY ;
4.4.4、复合索引
概念: 即一个索引包含多个列
1、KEY (customer_no,customer_name)
2、CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
4.4.5、基本语法
操作 | 命令 |
---|---|
创建 | CREATE [UNIQUE ] INDEX [indexName] ON table_name(column)) |
删除 | DROP INDEX [indexName] ON mytable; |
查看 | SHOW INDEX FROM table_name; |
使 用 Alter命令 | ALTER TABLE tbl_name ADD PRIMARY KEY (column_list) : 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为 NULL。 |
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。 | |
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。 |
4.5、索引的创建时机
4.5.1、适合创建索引的情况
- 主键自动建立唯一索引;
- 频繁作为查询条件的字段应该创建索引;
- 查询中与其它表关联的字段,外键关系建立索引;
- 单键/组合索引的选择问题, 组合索引性价比更高;
- 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度;
- 查询中统计或者分组字段;
4.5.2、不适合创建索引的情况
- 表记录太少;
- 经常增删改的表或者字段;
- Where 条件里用不到的字段不创建索引;
- 过滤性不好的不适合建索引;
4.6、Explain 性能分析
4.6.1、概念
使用 EXPLAIN 关键字可以模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理你的 SQL 语句的。分析你的查询语句或是表结构的性能瓶颈。
用法: Explain+SQL 语句。
Explain 执行后返回的信息:
4.6.2、各字段解释
1、id
select 查询的序列号,包含一组数字,表示查询中执行 select 子句或操作表的顺序。
①id 相同,执行顺序由上至下
②id 不同,如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行
id 如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id 值越大,优先级越高,越先执行
衍生 = DERIVED,比如就是由id为2的查询结果生成的表
关注点:id 号每个号码,表示一趟独立的查询。一个 sql 的查询趟数越少越好
2、select_type
select_type 代表查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询。
select_type 属性 | 含义 |
---|---|
SIMPLE | 简单的 select 查询,查询中不包含子查询或者 UNION |
PRIMARY | 查询中若包含任何复杂的子部分,最外层查询则被标记为 Primary |
DERIVED | 在 FROM 列表中包含的子查询被标记为 DERIVED(衍生)MySQL 会递归执行这些子查询, 把结果放在临时表里。 |
SUBQUERY | 在SELECT或WHERE列表中包含了子查询 |
DEPEDENT SUBQUERY | 在SELECT或WHERE列表中包含了子查询,子查询基于外层 |
UNCACHEABLE SUBQUERY | 无法使用缓存的子查询 |
UNION | 若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED |
UNION RESULT | 从UNION表获取结果的SELECT |
3、table
显示这一行的数据是关于哪张表的
4、type
type 是查询的访问类型。是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >ALL ,一般来说,得保证查询至少达到 range 级别,最好能达到 ref。
主要:system > const > eq_ref > ref > range > index > ALL
1、system
表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计
2、const
表示通过索引一次就找到了,const 用于比较 primary key 或者 unique 索引。因为只匹配一行数据,所以很快如将主键置于 where 列表中,MySQL 就能将该查询转换为一个常量。
3、eq_ref
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
4、ref
非唯一性索引扫描,返回匹配某个单独值的所有行.本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
没用索引前:
建立索引后:
5、range
只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引一般就是在你的 where 语句中出现了 between、<、>、in 等的查询这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。
6、index
Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
7、all
Full Table Scan,将遍历全表以找到匹配的行。
5、possible_keys
显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出, 但不一定被查询实际使用。
6、key
- 实际使用的索引。如果为NULL,则没有使用索引。
- 查询中若使用了覆盖索引,则索引和查询的select字段重叠
7、key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。 key_len 字段能够帮你检查是否充分的利用上了索引。ken_len 越长,说明索引使用的越充分。在不损失精确性的情况下,长度越短越好。
如何计算:
①先看索引上字段的类型+长度比如 int=4 ; varchar(20) =20 ; char(20) =20
②如果是 varchar 或者 char 这种字符串字段,视字符集要乘不同的值,比如 utf-8 要乘 3,GBK 要乘 2,
③varchar 这种动态字符串要加 2 个字节
④允许为空的字段要加 1 个字节
第一组:key_len=age 的字节长度+name 的字节长度=4+1 + ( 20*3+2)=5+62=67
第二组:key_len=age 的字节长度=4+1=5
8、ref
显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
9、rows
rows 列显示 MySQL 认为它执行查询时必须检查的行数。越少越好!
10、Extra
包含不适合在其他列中显示但十分重要的额外信息
Using filesort
说明 mysql 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL 中无法利用索引完成的排序操作称为“文件排序”。
出现 filesort 的情况:
优化后,不再出现 filesort 的情况:
查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。
Using temporary
使用了临时表保存中间结果,MySQL 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by。
优化前:
优化后:
Using index
Using index 表示相应的 select 操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!如果同时出现 using where,表明索引被用来执行索引键值的查找;如果没有同时出现 using where,表明索引只是用来读取数据而非利用索引执行查找。
Using where:表明使用了 where 过滤。
Using join buffer:使用了连接缓存。
impossible where:where 子句的值总是 false,不能用来获取任何元组。
select tables optimized away:在没有GROUPBY子句的情况下,基于索引优MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
distinct:优化distinct,在找到第一匹配的元组后即停止找同样值的工作。