MySQL的优化,至尊奢华版

什么是 MySQL优化?

MySQL作为当下最为时兴的数据库 之一,在自身的高效能执行任务的同时也会消耗着系统的资源,因业务需求的差异,执行的任务 所消耗的资源也大大不同。
不要小瞧这些资源,就是这么不起眼的微小资源,足以让你的MySQL在大数据量的情况下,发生宕机。

为什么要用到 MySQL优化

  • 系统的吞吐量瓶颈往往出现在数据库的访问速度上
  • 随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢
  • 数据是存放在磁盘上的,读写速度无法和内存相比(redis)

有一个名词叫 慢查询。

  • MySQL的慢查询,全名是慢查询日志
  • 是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阀值的语句。
  • 下面的优化方法,可以避免慢查询的出现。

MySQL慢查询 https://blog.csdn.net/weixin_44685869/article/details/104987675

当然再完美的 遵循优化 也不一定会 避免慢查询,慢查询就像 疾病一样 你再健康的身体 肚子也疼过吧,嗓子也咳嗽过吧。
所以在优化的基础上 再配合专业的解决办法,就是 在日志文件定义 最大查询的时间
具体是如何操作 下篇文章 介绍。因为还要介绍  slow_query_log 下篇文章再说,

本文只针对 MySQL的优化方法。

如何优化?

  1. 字段设计优化
  2. 引擎的选择
  3. 索引
  4. 查询缓存
  5. 分区
  6. 水平分割和垂直分割
  7. 集群
  8. SQL语句

字段设计优化

数据的精度:

MySQL中对于 浮点类型,有两种方案:float,decimal

  • float (浮点型):众所周知float会丢数据,什么时候丢呢?当浮点数转换为二进制都为0时候,就不会丢包。反之 丢包,存储类型值 32位。
  • double (浮点型):和float类似,但他的存储类型值 是64位。
  • decimal (定点型):decimal 精确每一位数。
  • 小数转整数:能不转尽量不转,也不要用 2.0 这样的小数来表示整数。

多精确一位数 就会多消耗一点资源(很小很小),所以根据情况的来选择 decimal 和 float。来实现MySQL的优化。

null空值:

在MySQL中,null 所代表的空值 计算逻辑比较复杂,没有 有值比空值都要好一些。

数据的定长 非定长

  • char是定长类型:超过长度的内容会被截取掉

  • varchar为非定长:对多余 长度的保存占用内存空间

字段的长度

字段的长度尽量不要过长。当然注释是需要的,预留字段也没法避免

外键

多逻辑外键,代替物理外键。
逻辑外检就代表,如果不看字段名和注释,此字段就是单一的类型,并不是 primary key

连级外键 尽量不要超过三张表

三范式

  • 第一范式:字段原子性

  • 第二范式:消除对主键的 部分依赖(可能主键不止一个)
    最好是使用与业务无关的字段作为主键

  • 第三范式:消除对主键的 传递依赖
    高内聚,如商品表可以分为 商品简介表,商品详情表


存储引擎的选择

MyISAM & InnoDB

功能差异:

  • InnoDB 比 MyISAM 多:事务的支持,行级锁,外键

存储差异:

  • 存储方式:
    MyISAM的数据是和索引分开存储的,而InnoDB是存在一起的

  • 表可移动性:
    可以移动表对应的 MYI(索引文件) MYD(数据文件)实现表的移动,而InnoDB还有额外的关联文件

  • 碎片空间
    MyISAM删除数据会产生碎片空间 (占用表文件空间),需要定期通过optimize table table-name 手动优化,而InnoDB不会。

  • 有序存储
    InnoBD插入数据时按照主键有序来插入,因此表中数据默认按主键有序 (耗费写入的时间,b+tree需要找插入点)

推荐选择

  • 读多写少用 MyISAM
    如:新闻网,小说网

  • 写多读少用 InnoDB
    InnoDB 支持事务,保证数据安全性、完整性。
    并发能力强(行锁)


索引

关键字与数据的映射关系称为索引(包含关键字和对应的记录在磁盘中的地址)。关键字是从数据当中提取的用于标识、检索数据的特定内容。

  • 关键字相对于数据本身,数据量小
  • 关键字是有序的,二分查找可快速确定位置

所以 使用索引访问数据是非常快的

索引类型:

  • 主键索引:
    要求关键字唯一且不为 bull

  • 普通索引:
    按照第一字段有序

  • 唯一索引:
    关键字的唯一

  • 全文索引:
    所有数据都要有索引

即使建立了索引,有些场景也不一定使用:
假如说 性别 这样的字段,一个关键字对应着很多条数据,使用索引会比全表扫描的效率还低。

所以 索引有种类,选择需谨慎

索引的存储结构:

  • btree:
    搜索多叉树:借点内关键字有序排列,关键字 之间有一个指针,查找效率 快的飞起。

  • b+tree:btree升级而来。数据和关键字存在一块空间,省去了 通过关键字找数据存放的地点时间。


查询缓存

将 select查询结果缓存起来,key 为SQL语句,value 为查询结果

缓存的数据也占用资源啊,所以 是否设置看你自己的定义了。


分区

一般情况下我们创建的表对应一组存储文件,当数据量较大时,MySQL的性能就会开始下降,这时我们就需要将数据分散到多组存储文件,保证其单个文件的执行效率。

最常见的分区方案是按id分区,如下将id的哈希值 将数据均匀分散到10个.ibd存储文件中:

在这里插入图片描述
就当成分页来理解。


水平分割和垂直分割

  • 水平分割:通过建立结构相同的几张表分别存储数据

  • 垂直分割:将经常一起使用的字段放在一个单独的表中,分割后的表记录之间是一一对应关系。

分表原因

  • 为数据库减压

  • 分区算法局限

  • 数据库支持不完善(5.1之后mysql才支持分区操作)


集群

MySQL集群是一个无共享的(shared-nothing)、分布式节点架构的存储方案,其目的是提供容错性和高性能。

读写分离

读写分离是依赖于主从复制,而主从复制又是为读写分离服务的。因为主从复制要求slave不能写只能读


SQL语句

  1. 尽量稍作计算
    Mysql的作用是用来存取数据的,不是做计算的,做计算的话可以用其他方法去实现,mysql做计算是很耗资源的。

  2. 尽量少 join
    MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL 优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在 Join 这方面所下的功夫还不够,所以性能表现离 Oracle 等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。

  3. 尽量少排序
      排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL的响应时间。
      对于MySQL来说,减少排序有多种办法,比如:
       通过利用索引来排序的方式进行优化
       减少参与排序的记录条数
       非必要不对数据进行排序

  4. 尽量避免 select *
      在数据量少并且访问量不大的情况下,select * 没有什么影响,但是量级达到一定级别的时候,在执行效率和IO资源的使用上,还是有很大关系的,用什么字段取什么字段,减少不必要的资源浪费。
    之前遇到过因为一个字段存储的数据比较大,并发高的情况下把网络带宽跑满的情况,造成网站打不开或是打开速度极慢的情况。

  5. 尽量用 join 代替子查询
      虽然 Join 性能并不佳,但是和 MySQL 的子查询比起来还是有非常大的性能优势。MySQL 的子查询执行计划一直存在较大的问题,虽然这个问题已经存在多年,但是到目前已经发布的所有稳定版本中都普遍存在,一直没有太大改善。虽然官方也在很早就承认这一问题,并且承诺尽快解决,但是至少到目前为止我们还没有看到哪一个版本较好的解决了这一问题。

  6. 尽量少 or
      当 where 子句中存在多个条件以“或”并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。

  7. 尽量用 union all 代替 union
    union 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。

  8. 尽量早过滤
      这一优化策略其实最常见于索引的优化设计中(将过滤性更好的字段放得更靠前)。
      在 SQL 编写中同样可以使用这一原则来优化一些 Join 的 SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表 Join,这样可以尽可能多的减少不必要的 IO 操作,大大节省 IO 操作所消耗的时间。

  9. 避免类型转换
      这里所说的“类型转换”是指 where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换:

  10. 尽可能对每一条运行在数据库中的SQL进行 explain

参考原址:https://www.nowcoder.com/discuss/150059?type=0&order=0&pos=8&page=0

发布了91 篇原创文章 · 获赞 174 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_44685869/article/details/104824958