Mysql系列-性能优化

1.硬件环境优化

许多不同的硬件都可能会影响都MySQL的性能,例如操作系统,磁盘大小,可用内存,CPU,网络以及各种计算机组件,最常见的瓶颈就是CPU/IO资源。
当数据可以放在内存中或者可以从磁盘中以足够快的速度读取时,CPU可能出现瓶颈;
另外,IO瓶颈,一般发生在工作所需的数据远远超过有效内存容量的时候。

  • 选择更快,多核CPU
  • 平衡内存和磁盘资源
  • 使用SSD固态磁盘
  • RAID磁盘阵列
  • 优化网络资源
  • 操作系统

2.缓存

默认情况先MySQL的查询缓存是开启的,MySql8.0之后默认关闭了缓存的功能

//查询缓存
show variables like '%query_cache%';

Mysql系列-性能优化_第1张图片

  • have_query_cache:是否支持缓存
  • query_cache_limit:select的结果集如果超过这个行数,将不会缓存
  • query_cache_min_res_unit:每次查询都是以块来申请内存空间,大小是4096K
  • query_cache_size:缓存大小超过设定的大小就不会缓存
  • query_cache_type:查询缓存的类型,值有 0(OFF)、1(ON)、2(DEMOND)。OFF表示查询缓存是关闭的。ON 表示查询总是先到查询缓存中去查找,除非在select 语句中包含sql_no_cache选项。 DEMOND 表示不适用缓存,除非在select 语句中包含sql_cache选项
  • query_cache_wlock_invalidate:该参数用于设置行级排它锁与查询缓存之间的关系,默认为为0(OFF),表示施加行级排它所的同时,该表的所有查询缓存依然有效。如果设置为1(ON),表示事假行级排它锁的同时,该表的所有查询缓存失效。
//查询缓存命中率
show status like 'Qcache%';

//查询缓存的总个数
show status like 'Com_select';

//结果集缓存
show variables like 'net_buffer_length';
show variables like 'max_allowed_packet';

//排序缓存
show variables like '%sort%';

//表缓存
show variables like 'table%';

//所有缓存
show variables like 'key%';

//日志缓存
show variables like '%binlog%cache%';

当然除了,MySQL服务自带的缓存机制,还可以借助外部的缓存,例如redis,Memcached等等

3.连接池

重用的数据库连接池有c3p0,dbcp,druid,Hikari,本身数据库的连接就需要占用资源,需要不断的建立连接,关闭连接,那么有了连接池之后,就可以连接复用,减少资源的消耗

4.读写分离

数据量非常庞大上千万级数据量时,可以考虑读写分离,只从复制,读库远远比写库多的情况下(一般读写比至少大于9:1),为了缓解主库的压力,将大多数读请求压力均摊到多个从库上。

5.分库分表

随着数据库业务的不断增长,数据库表里面的数据可能会越来越多,那么势必会造成查询的速度变慢,增删改查的开销也会越来越大,数据库的读写性能可能会成为业务发展的瓶颈。那么就可以把原本存储到一个库的数据分别存储到多个库上,把原本存储到一个表的数据分别存储到多个表上。

  • 分库:从单个数据库拆分成多个数据库的过程,将数据散落在多个数据库中。
  • 分表:从单张表拆分成多张表的过程,将数据散落在多张表内。
    例如可以把订单表,用户表,历史记录表原本都是放在一个数据库中,那么就可以进行拆分,订单做一个单独的库,用户做一个单独的库,记录做一个单独的库

还比如,订单表一年下来可能要一个表要存上百万的数据量,那么就可以把这个订单表进行拆分,例如可以按时间维度进行拆分,一年存一个订单表,下一年度的重新存一个订单表

6.慢日志查询

一般200毫秒到300毫秒之内可以接受,超过这个时间就会是慢sql

show variables like 'slow_query%';

慢sql 默认是关闭的

Mysql系列-性能优化_第2张图片
可以通过命令打开慢查询,但是MySQL 重启后会失效

set global slow_query_log=1

想要永久开启慢查询需要去my.in.cfg里面去修改配置文件

slow_query_log = 1
slow_query_log_file = /tmp/mysql_slow.log

可以借助mysqldumpslow日志分析工具来分析慢日志,找到那些慢sql 进行优化

7.explain

针对那些慢查询,去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,这是我们需要用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。

expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、extra

  • id:选择标识符
  • select_type:表示查询的类型。
  • table:输出结果集的表
  • partitions:匹配的分区
  • type:对表访问类型
  • possible_keys:表示查询时,可能使用的索引
  • key:表示实际使用的索引
  • key_len:索引字段的长度
  • ref:列与索引的比较
  • rows:扫描出的行数(估算的行数)
  • filtered:按表条件过滤的行百分比
  • Extra:执行情况的描述和说明
    重点解释一下select_type 和 type

select_type

  • (1) SIMPLE(简单SELECT,不使用UNION或子查询等)

  • (2) PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)

  • (3) UNION(UNION中的第二个或后面的SELECT语句)

  • (4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

  • (5) UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)

  • (6) SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)

  • (7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)

  • (8) DERIVED(派生表的SELECT, FROM子句的子查询)

  • (9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

type

常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)

  • ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

  • index: Full Index Scan,index与ALL区别为index类型只遍历索引树

  • range:只检索给定范围的行,使用一个索引来选择行

  • ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

  • eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

  • const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system

  • NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

8.表设计

良好的数据库设计能够减少数据冗余、降低数据库维护的成本、节约空间、高效访问,反之就会存在大量的数据冗余,存在数据插入、删除、更新异常,浪费大量的存储空间,访问效率低。

那么除了要遵守数据库设计的三大范式原则,还需要有字段的设计,索引的设计,主键外键的设计等等,这些都会影响到数据库的性能

  1. 整型类型的选择,例如整型类型就有5中,分别是tinyint,smallint,mediumint,int,bigint,这些类型都会占用存储长度,选择合适的类型进行存储可以减少冗余和磁盘空间;

  2. 还比如 时间类型的选择,时间类型也有好几种,有日期,时间,时间戳,年,时分秒,每个类型的长度也不一样

  3. char 和 varchar 的选择

char的长度是固定的255个字符,如果插入的长度小于定义长度时,则用空格填充
varchar 是可变的,根据存的字符长度来变化
正是由于char的长度是固定的,所有他的查询插入的效率要比varchar 高一些,有利也有弊

  1. ENUM
    存状态数据可以用ENUM类型,例如性别字段,国籍字段,名族字段等等,这样就不用存varchar了,大大减少了空间的开销

  2. 索引的设计
    这个就根据实际的业务情况来决定,具体需要用到哪些查询索引,根据业务来添加索引

  3. 还有就是选择合适的存储引擎,支持事物选择innodb,纯读,或者纯写选择myisam

9.SQL优化

  1. 不要使用select *,取出全部列,会让优化器无法完成索引覆盖扫描这类优化,还会带来额外的IO,内存和CPU的消耗;当然select * 也有个好处就是,在添加或删减字段不会对select * 有影响

  2. 包含NULL值的列不会被创建索引,所以where中is null 或者is not null都不会走索引

  3. like查询中,如果%like%会造成全表扫描,但是如果是like%,就会命中索引

  4. exists替代in,not in是效率比较低,因为要对子查询的表进行全表扫描

  5. union代替or,索引列上的or操作会造成索引失效,全表扫描

  6. 当只要一行数据时使用LIMIT1

  7. order by子句中不要使用非索引列或嵌套表达式,这样都会导致性能降低

  8. join 条件中把关联的字段加上索引

  9. 永远为每张表设置一个ID

  10. where中避免使用!= > < 表达式,否则索引失效,全表扫描

  11. 尽量避免where num/2 = 10这样的查询,改为where num = 10/2,就会走索引

  12. 索引并不是越多越好,过多的索引会造成写数据时效率变低

10.其他优化

例如限流,降级,负载均衡,队列,分布式等等
————————————————
版权声明:本文为CSDN博主「珍妮玛•黛金」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/woshiwangdaye/article/details/118966401

你可能感兴趣的:(数据库,高并发,服务性能排查,mysql,性能优化,数据库)