mysql的调优

调优的最终目的:节省系统资源、提高响应速度下面从6个维度对mysql进行优化。

第一步:对服务器的参数进行调优

通过show profile命令分析,如果sql语句在执行过程中等待时间长,就需要对mysql服务器的参数进行调优。

1.1优化服务器的硬件

服务器的硬件性能直接决定着MySQL数据库的性能:

  • 配置较大的内存:减少对磁盘的IO次数
  • 配置高速磁盘系统:提高磁盘IO的性能
  • 合理分布磁盘I/O
  • 配置多处理器:供多个线程使用

1.2优化mysql的参数

linux系统中在/etc/my.cnf中进行配置:

  • innodb_buffer_pool_size:表示缓冲池的大小,缓存索引的数据和表中的数据,该值越大查询速度越快,该值的大小取决于内存的大小。
  • key_buffer_size:表示索引缓冲区的大小,该缓冲区所有的线程共享,该值越大代表可以更好的处理索引,该值的大小取决于内存的大小。
  • table_cache:表示同时打开的表的个数。
  • query_cache_size:表示查询缓冲区的大小,sql语句查询时先到查询缓冲区中进行查询,如果查询缓冲区中没有才会到磁盘中进行获取。该参数需要和query_cache_type配合使用。
  • query_cache_type:表示缓冲区的类型

值是0时,所有的查询都不使用查询缓存区。但是query_cache_type=0并不会导致MySQL释放query_cache_size所配置的缓存区内存。

值是1时,所有的查询都将使用查询缓存区,除非在查询语句中指定SQL_NO_CACHE ,如SELECT SQL_NO_CACHE * FROM tbl_name。

当query_cache_type=2时,只有在查询语句中使用 SQL_CACHE 关键字,查询才会使用查询缓存区。

  • sort_buffer_size:表示需要进行排序的线程分配的缓冲区的大小。增加这个参数的值可以提高ORDER BY或GROUP BY操作的速度。该参数对应的分配内存也是每个连接独享。
  • join_buffer_size = 8M:表示联合查询操作所能使用的缓冲区大小。该参数对应的分配内存也是每个连接独享。
  • read_buffer_size:表示每个线程连续扫描时为扫描的每个表分配的缓冲区的大小(字节)。
  • innodb_flush_log_at_trx_commit:表示何时将缓冲区的数据写入日志文件,redo log的刷盘策略。
  • innodb_log_buffer_size:这是InnoDB存储引擎的事务日志所使用的缓冲区。当满足innodb_flush_log_trx_commit参数所设置的相应条件后,才会将缓冲区中的数据写入日志文件。
  • max_connections:表示允许连接到MySQL数据库的最大数量,默认值是151。这个连接数不是越大越好,因为这些连接会浪费内存的资源。过多的连接可能会导致MySQL服务器僵死。
  • back_log:用于控制MySQL监听TCP端口时设置的积压请求栈大小。如果MySql的连接数达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源,将会报错。
  • thread_cache_size:线程池缓存线程数量的大小
  • wait_timeout:指定一个请求的最大连接时间
  • interactive_timeout:表示服务器在关闭连接前等待行动的秒数。

系统配置参数的参考:

系统配置参数的参考
[mysqld]
port = 3306
serverid = 1
socket = /tmp/mysql.sock skip-locking #避免MySQL的外部锁定,减少出错几率增强稳定性。
skip-name-resolve #禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求! back_log = 384
key_buffer_size = 256M
max_allowed_packet = 4M
thread_stack = 256K
table_cache = 128K
sort_buffer_size = 6M
read_buffer_size = 4M
read_rnd_buffer_size=16M
join_buffer_size = 8M
myisam_sort_buffer_size =64M
table_cache = 512
thread_cache_size = 64
query_cache_size = 64M
tmp_table_size = 256M
max_connections = 768
max_connect_errors = 10000000
wait_timeout = 10
thread_concurrency = 8 #该参数取值为服务器逻辑CPU数量*2,在本例中,服务器有2颗物理CPU,而每颗物理CPU又支持H.T超线程,所以实际取值为4*2=8 skipnetworking #开启该选项可以彻底关闭MySQL的TCP/IP连接方式,如果WEB服务器是以远程连接的方式访问MySQL数据库服务器则不要开启该选项!否则将无法正常连接!
table_cache=1024
innodb_additional_mem_pool_size=4M #默认为2M innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=2M #默认为1M
innodb_thread_concurrency=8 #你的服务器CPU有几个就设置为几。建议用默认一般为8
tmp_table_size=64M #默认为16M,调到64-256最挂
thread_cache_size=120
query_cache_size=32M

第二步:优化表设计

数据表的设计也影响了SQL查询语句的效率

2.1表结构的设计遵循的范式

2.1.1表中键的概念



举例:

2.1.2表结构要尽量遵循三范式的原则,可以让数据结构更加清晰规范,减少冗余字段,减少在更新、插入、删除数据时发生的异常。

  • 第一范式(1NF):数据库表的每一列都是不可分割的基本数据项,一个列中不能包含其他列。

  • 第二范式(2NF):非主属性必须完全依赖于主键(尤其是复合主键),不能是部分依赖。

  • 第三范式(3NF):非主属性之间不能有依赖关系,确保非主属性与主键直接相关,而不是间接相关。

  • BCNF(巴斯范式):主属性不能对候选键有部分依赖或者传递依赖的关系。

  • 第四范式(4NF):一个表中不能存在多组一对多的关系,只能存在一组。

利用范式:范式等级越高,可以消除数据库的数据冗余,但是关联查询时降低查询的效率。

2.2可以利用反范式

反范式:在考虑到业务优先的情况下,可以通过在数据表中增加冗余字段来提高数据库的查询性能,这样就减少了关联查询,join表的次数,用空间换取时间。这些冗余这段不需要经常进行修改。

2.3优化数据类型

当数据量也越来越多的时候,你就不能只从系统稳定性的角度来思考问题了,还要考虑到系统整体的稳定性和效率。此时,优先选择符合存储需要的最小的数据类型。

  • 对整数类型数据进行优化

    遇到整数类型的字段可以用INT型。对于非负型的数据(如自增ID、整型IP)来说,要优先使用无符号整型UNSIGNED来存储。
  • 既可以使用文本类型也可以使用整数类型的字段,要选择使用整数类型。

    跟文本类型数据相比,大整数往往占用更少的存储空间。
  • 避免使用TEXT、BLOB数据类型

    在排序操作时,对于TEXT、BLOB数据类型的数据不能是用内存临时表,必须使用磁盘临时表。还需要进行二次查询进行回表。
  • 避免使用ENUM类型

    修改ENUM值需要使用ALTER语句,该类型的ORDER BY操作效率低,需要额外操作,使用TINYINT带代替。
  • 使用TIMESTAMP存储时间

    TIMESTAMP占4个字节,DATETIME使用8个字节,同时TIMESTAMP具有自动赋值以及自动更新的特性。
  • 用DECIMAL代替FLOAT和DOUBLE存储精确浮点数

    DECIMAL在财务类型的数据下要使用。

2.4ER模型

要素和数据表

2.5数据表的设计

数据表的设计原则:三少一多

  1. 数据表的个数越少越好
  2. 数据表中的字段个数越少越好
  3. 数据表中联合主键的字段个数越少越好
  4. 使用主键和外键越多越好

第三步:优化逻辑查询

逻辑查询优化就是改变sql语句的内容让sql执行效率更高,采用的方式时对sql语句进行等价交换,对查询进行重写。

3.1关联查询优化

3.1.1双表查询

1、当采用left join左外连接时,需要在右表的字段上建立索引。(驱动表是左表,被驱动表是右表,在被驱动表的join字段建立索引)

  • 建立索引:

    ALTER TABLE type ADD INDEX X (card); #【驱动表】,无法避免全表扫描

    ALTER TABLE book ADD INDEX Y (card); #【被驱动表】,可以避免全表扫描
  • explain分析sql语句:

    EXPLAIN SELECT SQL_NO_CACHE * FROM type LEFT JOIN book ON type.card = book.card;

2、当采用right join右外连接时,需要在左表的字段上建立索引。(驱动表是右表,被驱动表是左表,被驱动表的join字段上建立索引)

3、当采用inner join内连接时,会出现using join buffer。

  • 当只在一张表上建立索引,建立索引的表是被驱动表。

  • 当两张表都建立索引,被驱动表由mysql优化器自己决定,遵循小结果集驱动大结果集规则。

3.1.2join语句原理

可以使用straight_join让mysql使用固定的连接方式执行查询(左表为驱动表,右表为被驱动表)

1、join字段上有索引的情况

Index Nested-Loop Join(索引嵌套循环join)

表t1字段上没有索引,表t2字段上有索引,执行过程如下:

  1. 从表t1中读入一行数据R;
  2. 从数据行R中,取出a字段到表t2里利用索引去查找;
  3. 取出表t2中满足条件的行,跟R组成一行,作为结果集的一部分;
  4. 重复执行步骤1到3,直到表t1的末尾循环结束。

2、join字段上没有索引

Simple Nested-Loop Join(简单嵌套循环join)

如果join的列没有索引,先从驱动表中取一条数据,然后访问被驱动表,该表中的记录都会被加载到内存中,当匹配结束后清除内存中的数据,然后再从驱动表中加载一条记录,然后把被驱动表的记录在加载到内存匹配,这样周而复始,大大增加了l0的次数。为了减少被驱动表的IO次数,就出现了Block Nested-Loop Join的方式。

Block Nested-Loop Join(块嵌套循环join)

引入了join buffer缓冲区,将驱动表join相关的部分数据列(大小受join buffer的限制)缓存到join buffer缓冲区中,然后全表扫描被驱动表,被驱动表的每一条记录一次性和joinbuffer中的所有驱动表记录进行匹配(内存中操作),将简单嵌套循环中的多次加载被驱动表减少。

3、三种方式的开销比较
  • 整体效率:INLJ>BNLJ>SNLJ

  • 为被驱动表的join字段增加索引(减少内层表的join比较次数)
  • 需要JOIN 的字段,数据类型保持绝对一致,否则索引会失效。
  • 增加join buffer size的大小(减少内层表的扫描次数)
  • 减少驱动表的不必要字段查询(字段越少,join buffer中缓存的数据越多,减少内层表的扫描次数)
  • LEFT JOIN时,选择小表作为驱动表,大表作为被驱动表,减少外层循环的次数。
4、mysql8.0的对关联查询的优化

mysql8.0将BNLJ移除,引入了hash join

3.2子查询优化

子查询是MySQL的一项重要的功能,可以帮助我们通过一个SQL语句实现比较复杂的查询。但是,子查询的执行效率不高。

  • 执行子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表。这样会消耗过多的CPU和IO资源,产生大量的慢查询。
  • 子查询的结果集存储的临时表,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。
  • 对于返回结果集比较大的子查询,其对查询性能的影响也就越大。

可以将子查询进行优化,将子查询变为join多表连接查询,连接查询不需要建立临时表,速度比子查询快。

3.3排序优化

order by优化

1、在使用order by和group by中使用索引避免出现using filesort、using temporary。

  • where查询时使用范围时,order by进行排序时必须和索引定义顺序一致。
  • 单独使用order by语句时要遵循索引最左前列,否则会出现using filesort(order by后的字段与索引字段进行比较,如果顺序错、方向反都会导致索引失效,出现using filesort)
  • 单独使用order by时,如果数据量大,不使用limit进行限制也会出现using filesort
  • where字句与orderby字句条件列组合使用时,需要满足索引最左前列,否则会出现using filesort

2、当无法使用索引时,需要对filesort方式进行调优。

  • 双路排序:两次扫描磁盘,第一次读取磁盘对行指针和orderby列进行排序,第二次从磁盘读取已经排序好的字段在buffer中进行排序(两次扫描,IO耗时,因此出现了单路排序)

  • 单路排序:一次扫描磁盘,从磁盘中读取数据,按照orderby列在buffer对它们进行排序,然后扫描排序后的列表进行输出,效率更快,避免了二次读取数据并且把随机IO变成了顺序IO。但是消耗内存空间,可能一次不能读取全部的数据,导致多次IO。

  • 针对单独排序产生的问题(一次不能读取全部数据导致多次IO)进行参数调优:增大sort_buffer_size(该值的大小尽可能和max_length_for_sort_data的大小一致)

    如果总数据量小于max_length_for_sort_data就会用单路排序

    如果max_length_for_sort_data大于sort_buffer_size可能导致多次IO

    如果max_length_for_sort_data小于sort_buffer_size就会造成缓冲区的空间浪费

group by优化

  • group by实质是先排序后再进行分组,遵照索引建的最佳左前缀(和orderby原理一致)
  • 当无法使用索引列进行分组时,应该增大max_length_for_sort_data和sort_buffer_size的大小
  • where执行优先于having,尽量把限定条件写到where中
  • 减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。order by、group by、distinct这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。

3.4使用覆盖索引

覆盖索引:select查询的结果包含于索引列中就叫做覆盖索引。

索引列+主键 包含 SELECT 到 FROM之间查询的列 。

覆盖索引的好处

  • 避免innodb表进行索引的回表查询:二级索引的键值中可以获得想要查询的数据,就可以避免进行回表,减少了IO次数。
  • 把随机IO变成顺序IO加快查询效率:因为回表需要对磁盘进行随机IO,对索引是顺序IO查询。

覆盖索引的弊端

  • 索引字段的维护需要代价。

3.5使用索引下推(ICP)

当where查询条件中出现了索引列,但是该索引列是失效的状态,就需要进行索引下推,使该失效的索引列起到过滤作用。ICP是一种在存储引擎层使用索引过滤数据的一种优化方式。

没有使用ICP

storage:存储引擎会将匹配索引的索引列进行回表并取出整行记录返回server层

server:由server层评估WHERE后面的条件是否保留行。

使用ICP

storage:存储引擎首先将匹配索引的索引列的索引记录区间确定,然后使用索引下推让失效的索引列也进行过滤。满足条件的索引记录才去回表取出整行记录返回server层。

server:由server层评估WHERE后面的条件是否保留行。

举例:

1、创建索引:



2、执行语句:(lastname是索引列,但是是失效的状态,如果开启索引下推,就可以使用该列进行过滤)



ICP的优点

使用ICP减少了存储引擎访问基表的次数和mysql访问存储引擎的次数。

使用ICP的条件

  • 只能用于二级索引(secondary index)
  • explain显示的执行计划中type值(join 类型)为 range 、 ref 、 eq_ref 或者 ref_or_null 。
  • 如果where条件的字段不在索引列中,该列是不可以使用索引下推
  • ICP可以用于MyISAM和InnnoDB存储引擎
  • MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持。
  • 当SQL使用覆盖索引时,不支持ICP优化方法,因为覆盖索引不需要进行回表。

3.6EXISTS 和 IN 的区分

优化原则:用小的数据集驱动大的数据集

  • in:用小表查询出来的数据来驱动大表查询

  • exists:用小表查询出来数据,放到大表中做条件验证,根据验证结果(true或false)来决定小表的数据是否保留

3.7COUNT(*)与COUNT(具体字段)效率

  • COUNT(具体字段):来统计数据行数,要尽量采用二级索引。

  • COUNT(*)和COUNT(1):它们不需要查找具体的行,只是统计行数,系统会自动采用占用空间更小的二级索引来进行统计。如果有多个二级索引,会使用key_len小的二级索引进行扫描。当没有二级索引的时候,才会采用主键索引来进行统计。

3.8关于select(*)

  • 查询中应尽量避免使用*符号,应该使用具体的字段
  • 使用*符号无法使用覆盖索引

第四步:使用物理逻辑查询

物理逻辑的优化:主要是索引的创建和使用。(上一章有讲)

4.1优化插入记录的速度

MYISAM引擎的表:

  • 禁用索引:在对非空表插入记录之前,要禁用索引;如果未禁用索引在插入数据时,还需要对插入的记录建立索引,降低了插入记录的速度。

    禁用索引:alter table table_name disable keys;

    开启索引:alter table table_name enable keys;
  • 禁用唯一性检查:插入数据时,需要对记录进行唯一性校验,降低了插入数据的速度。

    禁用唯一性校验:set unique_checks=0;

    开启唯一性校验:set unique_checks=1;
  • 使用批量插入语句
  • 使用LOAD DATA INFILE批量导入数据:该操作比INSERT速度快

INNODB引擎的表

  • 禁用唯一性校验
  • 禁用外键检查
  • 禁止自动提交

第五步:使用redis或者memcached作为缓存

第六步:库级优化

6.1读写分离

一主一从:



双主双从:

6.2垂直分库

当数据量级达到千万级以上时,有时候我们需要把一个数据库切成多份,放到不同的数据库服务器上,减少对单一数据库服务器的访问压力。

6.3垂直分表和水平分表

垂直拆分的优点: 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。

垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起JOIN操作。此外,垂直拆分会让事务变得更加复杂。

6.4拆分数据表:冷热数据分离

将一张表中的数据分开,提交查询效率:

  • 热数据:表中字段的操作频率高的数据
  • 冷数据:表中字段操作频率低的数据

冷热分离数据的目的:

  • 减少磁盘IO:当数据分离时,一个页中可以存储更多的数据,这样在读取时可以减少磁盘的IO。
  • 更有效的利用缓存:避免无用的数据读入缓存

6.5增加中间表

把经常联合查询的数据插入中间表中,然后将原来的联合查询改为对中间表的查询,以此来提高查询的效率。

6.6使用非空约束

使用非空约束的好处:

  • 减少了对NULL值的字段判断是否为空的开销,提高存储效率。
  • 索引NULL列需要额外的空间来保存

10、mysql的调优的更多相关文章

  1. MySQL性能调优的10个方法 - mysql数据库栏目

    摘要: https://edu.aliyun.com/a/29036?spm=5176.11182482.related_article.1.hbeZbF 摘要: MYSQL 应该是最流行了 WEB ...

  2. MySQL性能调优与架构设计——第10章 MySQL数据库Schema设计的性能优化

    第10章 MySQL Server性能优化 前言: 本章主要通过针对MySQL Server(mysqld)相关实现机制的分析,得到一些相应的优化建议.主要涉及MySQL的安装以及相关参数设置的优化, ...

  3. mysql技术调优资料整理

    1,15 个有用的 MySQL/MariaDB 性能调整和优化技巧 2,MariaDB设置主从复制 3,CentOS6.4安装mysql2redis        http://www.cnblogs ...

  4. MySQL性能调优——锁定机制与锁优化分析

    针对多线程的并发访问,任何一个数据库都有其锁定机制,它的优劣直接关系着数据的一致完整性与数据库系统的高并发处理性能.锁定机制也因此成了各种数据库的核心技术之一.不同数据库存储引擎的锁定机制是不同的,本 ...

  5. MySQL性能优化总结___本文乃《MySQL性能调优与架构设计》读书笔记!

    一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...

  6. MySql(十一):MySQL性能调优——常用存储引擎优化

    一.前言 MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.本章将介绍最为常用的两种存储引擎进行针对性的优化建议. 二.MyISAM存储 ...

  7. MySQL性能调优与架构设计——第 18 章 高可用设计之 MySQL 监控

    第 18 章 高可用设计之 MySQL 监控 前言: 一个经过高可用可扩展设计的 MySQL 数据库集群,如果没有一个足够精细足够强大的监控系统,同样可能会让之前在高可用设计方面所做的努力功亏一篑.一 ...

  8. MySQL性能调优与架构设计——第 16 章 MySQL Cluster

    第 16 章 MySQL Cluster 前言: MySQL Cluster 是一个基于 NDB Cluster 存储引擎的完整的分布式数据库系统.不仅仅具有高可用性,而且可以自动切分数据,冗余数据等 ...

  9. MySQL性能调优与架构设计——第13章 可扩展性设计之 MySQL Replication

    第13章 可扩展性设计之 MySQL Replication 前言: MySQL Replication 是 MySQL 非常有特色的一个功能,他能够将一个 MySQL Server 的 Instan ...

随机推荐

  1. Html 项目使用自定义字体文件问题

    感谢大佬:https://zhidao.baidu.com/question/652711582735059245.html 1.首先在项目过程中新建文件夹fonts将准备好的ttf字体文件复制该文件 ...

  2. argc 和 argv

    转载请注明来源:https://www.cnblogs.com/hookjc/ 如果用C寫一般的命令列工具,常透過main函式的argc,argv來取得使用者所輸入的命令參數.int main(int ...

  3. Java程序性能监控工具

    系统性能监控: 确定系统运行的整体状态,基本定位问题所在 uptime命令 [root@localhost ~]# uptime23:19:38 up 244 days, 3:39, 34 users ...

  4. Shell for&while中的循环

    #!/usr/bin/ksh #数字段形式 for i in {1..10} do echo $i done #详细列出(字符且项数不多) for File in 1 2 3 4 5 do echo ...

  5. k8s补充

    k8s补充 容器云发展及主要内容 1.云计算,交付标准(iaas--openstack) 国内:阿里云一华为云(振兴杯)百度云(私有云) 国外:AWS 2.平台即服务(PAAS) 例如:新浪云(号称免 ...

  6. JavaGuide--Java篇

    本文避免重复造轮子,也是从JavaGuider中提取出来方便日后查阅的手册 参考链接: JavaGuider:https://javaguide.cn/java/basis/java-basic-qu ...

  7. LeetCode随缘刷题之两数相加

    逐步解释,有说错的地方欢迎指正. package leetcode.day_12_03; /** * 给你两个非空 的链表,表示两个非负的整数.它们每位数字都是按照逆序的方式存储的,并且每个节点只能存 ...

  8. 初探Matrix Android ApkChecker

    背景 因为我所在的项目是做投放包,对安卓包的大小很敏感,经常会优化包的大小,所以想引入工具静态检测包大小,看能不能找到其中可以优化的地方,防患于未然.Matrix是微信终端自研和正在使用的一套APM( ...

  9. Linux基础:VLAN篇

    一.二层基础知识 1.1 vlan介绍 本小节重点: vlan的含义 vlan的类型 交换机端口类型 vlan的不足 1.1.1 vlan的含义 局域网LAN的发展是VLAN产生的基础,因而先介绍一下 ...

  10. Solution -「CF 1237E」Balanced Binary Search Trees

    \(\mathcal{Description}\)   Link.   定义棵点权为 \(1\sim n\) 的二叉搜索树 \(T\) 是 好树,当且仅当: 除去最深的所有叶子后,\(T\) 是满的: ...