博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
性能优化-mysql
阅读量:2381 次
发布时间:2019-05-10

本文共 6024 字,大约阅读时间需要 20 分钟。

文章目录

1.认识mysql

1.1 架构图

1.1.1 简介

image.png | left | 747x560

大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。

Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎(存储引擎是基于表的!)。

1.1.2 详细

上面是宏观图,下面是详细图

image.png | left | 578x394

image.png | left | 590x822

  • 初始化模块:数据库引擎的配置、端口、缓存等数据初始化

  • 连接模块:初始化完成之后模块会监听请求,当有请求进来分配一个线程,模块作用是管理数据库连接池(与线程池原理类似)

  • 用户模块:请求拿到之后会去验证一下用户权限

  • 命令分发器:授权通过之后会对请求进行判断分发(mysql有query与comand两种命令)

  • 命令解析器:对语句进行解析(parse)与执行计划分析(explain)进如不同的执行模块

  • 执行模块:查询优化器、表变更、表维护、复制模块(master,slaver)、状态模块

  • 访问控制模块:所有连接又重新指向该模块进行访问控制

  • 表管理模块

  • 存储引擎接口:目前各种数据库产品中,基本上只有 MySQL 可以实现其底层数据存储引擎的插件式管理。这个模块实际上只是 一个抽象类,但正是因为它成功地将各种数据处理高度抽象化,才成就了今天 MySQL 可插拔存储引擎的特色

  • 查询缓存模块:会把查询语句与查询结果缓存起来(键值对),如果有缓存就不走命令解析

#查询缓存show variables like 'have_query_cache';
  • 日志模块:binlog,redo,undo日志
  • 核心API:类似JVM的部分功能,一个manner,对内存进行管理

1.2 存储引擎介绍

mysql存储是基于表的,schema对应在本地是一个目录(~/mysql5.6/data/),表对应两个存储文件:xx.ibd与xxx.frm

image.png | left | 558x487

Innodb索引与数据放在一个文件中,索引是基于主键展开

Myisam 两个文件,一个索引文件,一个数据文件

count有专门存储的地方(Innodb优化->分页的count(1)可以缓存起来)

2.性能

2.1 影响性能的因素

  • 人为因素:需求
  • 程序员因素:过于面向对象

查询文章表的前10篇文章的评论数

方法1:面向对象->查询前10篇文章、根据文章id查询评论数(消耗了1+10 = 11次IO)
方法2:查询10篇文章、根据文章id集合group by查询(消耗1+1 = 2次IO)

  • cache:缓存设计缺陷,都打到数据库层面了
  • 对可拓展的过度追求:泛型、扩展字段、冗余字段,导致表字段过多出现问题
  • 表范式:对表的不合理拆分
  • 应用场景 :

OLTP (on-line transaction processing)

image.png | left | 647x379

OLAP (On-Line Analytical Processing)

image.png | left | 636x418

2.2 索引原理

2.2.1 索引简介

select * from t_user where seq_id=2;

如果没有索引的话,该语句会轮询全表扫描

如果有索引的话,那么直接查询索引,找到索引后对应有个数据存储地址

image.png | left | 284x114

索引结构图

image.png | left | 607x627

2.2.2 几种索引

1)B-Tree索引

一般来说,MySQL中的B-Tree索引的物理文件大多都是以BalanceTree的结构来存储的,也就是所有实际需要的数据都存放于Tree的LeafNode,而且到任何一个LeafNode的最短路径的长度都是完全相同的,所以我们大家都称之为B-Tree索引当然,可能各种数据库(或MySQL的各种存储引擎)在存放自己的B-Tree索引的时候会对存储结构稍作改造。如Innodb存储引擎的B-Tree索引实际使用的存储结构实际上是B+Tree,也就是在B-Tree数据结构的基础上做了很小的改造,在每一个LeafNode上面出了存放索引键的相关信息之外,还存储了指向与该LeafNode相邻的后一个LeafNode的指针信息,这主要是为了加快检索多个相邻LeafNode的效率考虑。

2)Hash索引

Hash索引在MySQL中使用的并不是很多,目前主要是Memory存储引擎使用,而且在Memory存储引擎中将Hash索引作为默认的索引类型。所谓Hash索引,实际上就是通过一定的Hash算法,将需要索引的键值进行Hash运算,然后将得到的Hash值存入一个Hash表中。然后每次需要检索的时候,都会将检索条件进行相同算法的Hash运算,然后再和Hash表中的Hash值进行比较并得出相应的信息。

Hash索引仅仅只能满足“=”,“IN”和“<=>”查询,不能使用范围查询;

Hash索引无法被利用来避免数据的排序操作;
Hash索引不能利用部分索引键查询;
Hash索引在任何时候都不能避免表扫面;
Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高;

3)Full-text索引

Full-text索引也就是我们常说的全文索引,目前在MySQL中仅有MyISAM存储引擎支持,而且也并不是所有的数据类型都支持全文索引。目前来说,仅有CHAR,VARCHAR和TEXT这三种数据类型的列可以建Full-text索引。

索引能够极大的提高数据检索效率,也能够改善排序分组操作的性能,但是我们不能忽略的一个问题就是索引是完全独立于基础数据之外的一部分数据,更新数据会带来的IO量和调整索引所致的计算量的资源消耗。

2.2.3 几种树

红黑树、B-Tree、B+Tree

树插入实验网址:

为什么不用红黑树?因为红黑树的深度不可控,查询的时候数据多就太深了

image.png | left | 384x216

B树:不管数据多大,查询深度都是固定的

B-Tree:数据与节点存在一起

image.png | left | 194x153

例如

image.png | left | 566x323

B+Tree:数据都放在叶子节点上,其他节点是key

image.png | left | 404x162

例如

image.png | left | 502x319

2.2.4 Myisam与Innodb的索引树结构图

Myisam

image.png | left | 827x291

查询id为1的数据时,会去B+Tree索引搜索,找到id=1对应的地址后,再去MYD文件里面定位

Innodb

image.png | left | 827x419

Innodb的数据本身就存在索引树里面,在Myisam里面以给那么加索引,那么name会指向数据地址,但是在这边,不能指向数据地址,要指向主键。

表结构:id user_id create_time

复合索引:(user_id,create_time)
当查询user_id为2的用户日志时,不需要排序,因为索引已经排序好了!!
select * from t_user_log where user_id=2 ;

2.3锁

2.3.1 行锁

image.png | left | 827x460

#行锁查询show status like 'innodb_row_lock%';

2.3.2 表锁

image.png | left | 504x310

#表锁查询show status like 'table%';

2.3.3 页锁

image.png | left | 390x119

2.3.4 死锁的发生

行锁的情况下会出现死锁,表锁不会出现死锁

image.png | left | 786x396

2.3.5 共享锁与排它锁

image.png | left | 827x230

2.4优化

2.4.1 原则

image.png | left | 723x274

2.4.2 explain 执行计划

在sql语句前面添加explain进行语句分析 参考

id
SELECT识别符。这是SELECT的查询序列号
select_type
SELECT类型,可以为以下任何一种:
  • SIMPLE:简单SELECT(不使用UNION或子查询)
  • PRIMARY:最外面的SELECT
  • UNION:UNION中的第二个或后面的SELECT语句
  • DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
  • UNION RESULT:UNION 的结果
  • SUBQUERY:子查询中的第一个SELECT
  • DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
  • DERIVED:导出表的SELECT(FROM子句的子查询)
table
输出的行所引用的表
type
联接类型。下面给出各种联接类型,按照从最佳类型到最坏类型进行排序:
  • system:表仅有一行(=系统表)。这是const联接类型的一个特例。
  • const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次!
  • eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。
  • ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。
  • ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。
  • index_merge:该联接类型表示使用了索引合并优化方法。
  • unique_subquery:该类型替换了下面形式的IN子查询的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
  • index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
  • range:只检索给定范围的行,使用一个索引来选择行。
  • index:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
  • ALL:对于每个来自于先前的表的行组合,进行完整的表扫描。
possible_keys
指出MySQL能使用哪个索引在该表中找到行
key
显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。
key_len
显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。
ref
显示使用哪个列或常数与key一起从表中选择行。
rows
显示MySQL认为它执行查询时必须检查的行数。多行之间的数据相乘可以估算要处理的行数。
filtered
显示了通过条件过滤出的行数的百分比估计值。
Extra
该列包含MySQL解决查询的详细信息
  • Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
  • Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
  • range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
  • Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。
  • Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
  • Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。
  • Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
  • Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
  • Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。

2.4.3 Profiling性能分析

set profiling=1;select nickname,count(*) from user group by nickname;show profiles;show profile cpu,block io for query 75;(75是show profiles的id)

2.4.4 join底层实现

原理图解

image.png | left | 826x588

A表当做驱动表(小结果集)驱动B表(大结果集),联表查询得出result

当出现C表之后,A与B表的join会产生join buffer再与C表进行关联得出result

show variables like 'join_%';#查join的buffer大小等

image.png | left | 524x218

2.4.5 order by底层实现

实现原理图解

image.png | left | 671x291

先把user表的birthday字段拷贝到buffer进行排序,然后返回实际数据地址,再进行处理得出result(做了两次IO)

image.png | left | 658x479

第二种方式是把数据需要返回的字段都拷贝到内存进行排序,指针指向的是内存中的数据地址,排序后直接返回result,空间换时间(所以尽量少使用select * )

这两种排序方式是mysql自动选择的,如果buffer够用就用第二种

show variables like '%sort%';#查询order by排序缓存的大小

概览图

image.png | left | 827x327

2.4.6 group by底层实现

group by与order by类似,它会先排序然后分组

2.4.7 distinct

distinct是基于group by的结果进行计算的

2.4.8 limit

#分页查找SELECT * FROM user limit 10000,10;#offset很大的时很慢,因为要取10010这么多条数据#根据索引进行优化SELECT * FROM user where id> 10000 limit 10;

2.4.9 union

join是笛卡尔积,union是叠加

2.4.10 性能优化

当定位到是数据库出现性能问题的时候可以进行如下优化排查

#show sql配置,慢查询日志[mysqld]show_query_log=1show_query_log_file=/path/to/filelong_query_time=0.2log_output=FILE

image.png | left | 663x414

通过show full processlist定位当前卡住的查询语句,然后对该语句进行explain分析,再对照explain表格进行分析,看是不是没用到索引

3.参考

转载地址:http://kvmxb.baihongyu.com/

你可能感兴趣的文章
JVM 类加载机制、对象的创建过程
查看>>
SpringBoot整合AOP
查看>>
消息中间件 MQ
查看>>
Spring | SpringBoot 理论总结
查看>>
Redis 简介、安装、配置、启动、连接
查看>>
Redis 集群、哨兵、主从同步
查看>>
在Java中操作Redis,使用Redis实现分布式锁
查看>>
MySQL 事务
查看>>
SpringCloud Ribbon 负载均衡
查看>>
SpringCloud Feign 声明式服务调用
查看>>
JVM 垃圾回收机制、垃圾收集器、调优参数
查看>>
JDK自带的JVM工具
查看>>
SpringCloud Hystrix 容错保护
查看>>
SpringCloud Zuul 网关
查看>>
SpringCloud 分布式链路追踪、分布式日志系统
查看>>
SpringCloud Config 配置管理
查看>>
富文本编辑器wangEditor
查看>>
一种适合中小团队的的Android自动化压力测试方案
查看>>
CNNs在图像压缩领域的运用——An End-to-End Compression Framework Based on Convolutional Neural Networks
查看>>
今天 把git攻克了
查看>>