MySQL:MySQL 性能优化思路

影响 MySQL 性能的几个方面

  • 服务器硬件 & 服务器系统(硬件 & 系统参数优化)
    • 一般是运维来负责
  • 存储引擎
    • MyISAM: 不支持事务,表级锁。
    • InnoDB: 支持事务,支持行级锁,事务 ACID。
  • 数据库参数配置

  • 数据库 结构设计 & SQL 语句优化(重点优化方向)

读写分离 & 一主多从

工作原理

  • 在实际的应用中,绝大部分情况都是读远大于写;
  • Mysql提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在 Master和Slave机器上进行;
  • Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂 Slave,通过此方式可以有效的提高DB集群的 QPS;
  • 所有的写操作都是先在Master上操作,然后同步更新到Slave上;
  • 所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

应用实践

  • 当读压力很大的时候,可以考虑添加 Slave 机器的分式解决,
    • 但是当 Slave 机器达到一定的数量就得考虑分库了。
  • 当写压力很大的时候,就必须得进行分库操作。

MySQL引擎选择

InnoDB

  • 特点
    • 支持事务,行级锁,外键,崩溃修复,多版本并发控制;
    • 读写效率相对较差,内存使用相对较高,占用数据空间相对较大。
  • 应用场景
    • 依赖于 事务,回滚,并发,大数据量,外键,行级锁 的场景。

MyISAM

  • 特点

    • 不支持事务,不支持外键,仅支持非聚集索引;

    • 支持全文索引,仅支持到表级锁;

    • 支持数据压缩,占用空间相对小,内存使用相对较低;

    • 读写性能相对极佳。

  • 应用场景

    • 过多的大数据量的频繁的查询优势。

Memory

  • 特点

    • 依赖于内存空间,数据处理速度快,仅支持到表级锁。
  • 应用场景

    • 临时性的,大数据量表的查询优势。

MySQL分库分表

分库分表的基本原理

  • 为什么要分库分表
    • 用户请求量太,但是单服务器 TPS,内存,IO 都是有限的;
    • 单库太大,单库所在服务器上磁盘空间不足,单库处理能力有限,存在 IO 瓶颈;
    • 单表太大,索引膨胀,查询超时;
  • 分库分表的目标
    • 分表,可以解决单表海量数据的读写性能问题;
    • 分库,可以解决单台数据库的并发访问压力问题。
  • 拆分思路
    • 垂直拆分,垂直分库、垂直分表
    • 水平拆分,水平分库、水平分表

      垂直拆分:是指按功能模块拆分,垂直拆分解决表与表之间的 I/O 竞争。比如分为订单库、商品库、用户库…这种方式多个数据库之间的表结构不同。 水平拆分:将同一个表的数据进行分块保存到不同的数据库中,水平拆分解决单表中数据量增长出现的压力。这些数据库中的表结构完全相同。

  • 分库分表的顺序 分库分表的顺序应该是先垂直分,后水平分。因为垂直分更简单,更符合我们处理现实世界问题的方式。

垂直分表

垂直分表,是基于列(字段)对表格进行横向拆分。

  • 垂直分表规则:
    • 数据较大的字段,单独存表;
    • 不常用的的字段,单独存表;
    • 经常一起使用的字段,放在一起存表;
    • 长度较长(比如text类型字段)的字段,单独存表;

      垂直分表,一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页”问题。

分表能够解决单表数据量过大带来的查询效率下降的问题,但是,却无法给数据库的并发处理能力带来质的提升。面对高并发的读写访问,当数据库master服务器无法承载写操作压力时,不管如何扩展slave服务器,此时都没有意义了。因此,我们必须换一种思路,对数据库进行拆分,从而提高数据库写入能力,这就是所谓的分库。

垂直分库

垂直分库,是针对一个系统中的不同业务进行拆分,比如用户User一个库,商品Producet一个库,订单Order一个库。

垂直切分后,一般放在多个服务器上,而不是一个服务器上。这是因为,一个购物网站对外提供服务,会有用户,商品,订单等的CRUD。没拆分之前, 全部都是落到单一的库上的,这会让数据库的单库处理能力成为瓶颈。

按垂直分库后,如果还是放在一个数据库服务器上, 随着用户量增大,这会让单个数据库的处理能力成为瓶颈,还有单个服务器的磁盘空间,内存,tps等非常吃紧。 所以我们要拆分到多个服务器上,这样上面的问题都解决了,以后也不会面对单机资源问题。 数据库往往最容易成为应用系统的瓶颈,而数据库本身属于“有状态”的,相对于Web和应用服务器来讲,是比较难实现“横向扩展”的。 数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈。数据库业务层面的拆分,能对不同业务的数据分别的进行管理,维护,监控,扩展等。

水平分表(不单独使用)

针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。

  • 水平分表的问题:
    • 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。
    • 无法进行跨表直连连接查询;
    • 统计数据不方便;
    • 如果数据持续增长,达到现有分表的瓶颈,需要增加分表时、会出现数据重新排列的情况。

      生产环境中,水平分表一般不单独使用,而是和水平分库一起使用,做水平分库分表。

水平分库(一般与水平分表同时使用)

将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。

  • 水平分库分表策略:
    • 用户 id 取模;
    • 如果不是整数,可以进行 hash 获取到整数;
    • 按照地理区域拆分;
    • 按照时间拆分;
    • 按照【冷热数据】拆分;

分库分表的标准

  • 什么样的情况需要分库分表:
    • 表体积大于 2G,行数大于 1000 万;
    • 表中含有 text、blob、varchar(1000);
    • 数据有时效性,可以单独拿出来归档;
  • 分库分表的大小多少合适 分表最大分1024,一般分100左右比较适合。

分库分表存在的问题

  • 维度的问题 假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的 购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找 到买人的交易记录比较麻烦。

    维度的问题解决办法:记录【两份数据】,一份按照用户纬度分表,一份按照商品维度分表。

  • 联合查询的问题 联合查询基本不可能,因为关联的表有可能不在同一数据库中。这是因为分库分表后表之间的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表, 结果原本一次查询能够完成的业务,可能需要多次查询才能完成。 联合查询问题的解决方法:
    • 全局表:基础数据,所有库都拷贝一份;
    • 字段冗余:这样有些字段就不用join去查询了;
    • 系统层组装:分别查询出所有,然后组装起来,较复杂。
  • 跨库事务问题 避免在一个事务中修改db0中的表的时候、同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响。 分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
  • 数据依赖问题 例如卖家a的商品和交易信息都放到db0中,当db1挂了的时候,卖家a相关的东西可以正常使用。尽量把同一组数据放到同一DB服务器上,避免数据库中的数据依赖另一数据库中的数据。

分库分表产品方案

  • MySQL Proxy;
  • Amoeba;
  • Hibernate Shards;
  • sharding-jdbc;

MySQL分区分片

分区原理

  • 表分区,就是将数据量比较大的表,在物理上分成若干个小表,从逻辑来看还是一个大表。MySQL 5 之后才有了数据表分区功能。
  • 数据库的应用分为两类:一类是OLTP(在线事务处理),如Blog、电子商务、网络游戏等;另一类是OLAP(在线分析处理),如数据仓库、数据集市。
  • 对于OLAP的应用,分区的确是可以很好地提高查询的性能。 因为OLAP应用大多数查询需要频繁地扫描一张很大的表。假设有一张1亿行的表,其中有一个时间戳属性列。用户的查询需要从这张表中获取一年的数据。如果按时间戳进行分区,则只需要扫描相应的分区即可。
  • 对于OLTP的应用,分区应该非常小心。 在这种应用下,通常不可能会获取一张大表10%的数据,大部分都是通过索引返回几条记录即可。而根据B+树索引的原理可知,对于一张大表,一般的B+树需要2~3次的磁盘IO。因此B+树可以很好地完成操作,不需要分区的帮助,并且设计不好的分区会带来严重的性能问题。

    MySQL的分区字段,必须包含在主键字段内。

分区策略

  • RANGE分区
    • 最常用的一种分区类型,基于属于一个给定连续区间的列值,把多行分配给分区。这些区间要连续且不能相互重叠,使用VALUES LESS THAN操作符来进行定义。
  • LIST分区
    • LIST分区和RANGE分区类似,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择,而非连续的。
    • LIST分区通过使用“PARTITION BY LIST(expr)”来实现,其中“expr” 是某列值或一个基于某个列值、并返回一个整数值的表达式,然后通过“VALUES IN (value_list)”的方式来定义每个分区,其中“value_list”是一个通过逗号分隔的整数列表。
    • 不同于RANGE分区中定义的VALUES LESS THAN语句,LIST分区使用VALUES IN,因为每个分区的值是离散的,因此只能定义值。
  • HASH分区
    • HASH分区的目的是将数据均匀地分布到预先定义的各个分区中,保证各分区的数据量大致都是一样的。在RANGE和LIST分区中,必须明确指定一个给定的列值或列值集合应该保存在哪个分区中;而在HASH分区中,MySQL自动完成这些工作,用户所要做的只是基于将要进行哈希分区的列值指定一个列值或表达式,以及指定被分区的表将要被分隔成的分区数量。
    • 要使用HASH分区来分割一个表,要在CREATE TABLE 语句上添加一个“PARTITION BY HASH (expr)”子句,其中“expr”是一个返回一个整数的表达式。它可以仅仅是字段类型为MySQL 整型的一列的名字。此外,你很可能需要在后面再添加一个“PARTITIONS num”子句,其中num是一个非负的整数,它表示表将要被分割成分区的数量,如果没有包括一个PARTITIONS子句,那么分区的数量将默认为1。

分区使用场景

  • 一张表的查询速度已经慢到影响使用的时候;
  • 表中的数据是分段的;
  • 对数据的操作往往只涉及一部分数据,而不是所有的数据;
  • 数据库比较多、并发不多,可以采用表分区;
  • 数据量比较大、并发较高,可以采用分库分表和分区相结合;

谨慎使用 MySQL 分区表

  • 分区表在物理上表现为多个文件,在逻辑上表现为一个表;
  • 谨慎选择分区键,跨分区查询效率可能更低;
  • 建议采用物理分表的方式管理大数据。

分表和分区的区别

  • 实现方式
    • mysql的分表是真正的分表,一张表分成很多表后,每一个小表都是完正的一张表,都对应三个文件(MyISAM引擎:一个.MYD数据文件,.MYI索引文件,.frm表结构文件)。
  • 数据处理
    • 分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。分区则不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表还是一张表,数据处理还是由自己来完成。
  • 提高性能
    • 分表后,单表的并发能力提高了,磁盘I/O性能也提高了。分区突破了磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。 在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。
  • 实现的难易度
    • 分表的方法有很多,用merge来分表,是最简单的一种方式。这种方式和分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。 分区实现是比较简单的,建立分区表,跟建平常的表没什么区别,并且对代码端来说是透明的。

分片策略

  • 分片,是把数据库横向扩展(Scale Out)到多个物理节点上的一种有效的方式。
    • 分片的主要目的,是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题。Shard这个词的意思是“碎片”。如果将一个数据库当作一块大玻璃,将这块玻璃打碎,那么每一小块都称为数据库的碎片(DatabaseShard)。将整个数据库打碎的过程就叫做分片,可以翻译为分片。
  • 形式上,分片可以简单定义为将大数据库分布到多个物理节点上的一个分区方案。
    • 每一个分区包含数据库的某一部分,称为一个片,分区方式可以是任意的,并不局限于传统的水平分区和垂直分区。
    • 一个分片可以包含多个表的内容甚至可以包含多个数据库实例中的内容。每个分片被放置在一个数据库服务器上。一个数据库服务器可以处理一个或多个分片的数据。系统中需要有服务器进行查询路由转发,负责将查询转发到包含该查询所访问数据的分片或分片集合节点上去执行。

分片和分区的区别

  • 分片和分区,有很多的相似之处。有的时候,分片(Sharding) 也被近似等同于水平分区(Horizontal Partitioning),网上很多地方也用水平分区来指代 分片(Sharding)。

    分片和分区的区别

MySQL锁优化

innodb 锁优化

Innodb 存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但是在整体并发处理能力方面要远远优于MyISAM 的表级锁定的。

  • 尽可能让所有的数据检索都通过索引来完成,从而避免Innodb 因为无法通过索引键加锁而升级为表级锁定;
  • 合理设计索引,让Innodb 在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他Query 的执行;
  • 尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定的记录;
  • 尽量控制事务的大小,减少锁定的资源量和锁定时间长度;
  • 在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少MySQL 因为实现事务隔离级别所带来的附加成本;

减少 innodb 死锁产生概率的建议

  • 类似业务模块中,尽可能按照相同的访问顺序来访问,防止产生死锁;
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
  • 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

MyISAM 锁优化

  • MyISAM 表锁优化建议优化MyISAM 存储引擎锁定问题的时候,最关键的就是如何让其提高并发度。由于锁定级别是不可能改变的了,所以我们首先需要尽可能让锁定的时间变短,然后就是让可能并发进行的操作尽可能的并发。

缩短锁定时间

  • 尽两减少大的复杂Query,将复杂Query 分拆成几个小的Query 分布进行;
  • 尽可能的建立足够高效的索引,让数据检索更迅速;
  • 尽量让MyISAM 存储引擎的表只存放必要的信息,控制字段类型;
  • 利用合适的机会优化MyISAM 表数据文件;

分离能并行的操作

配置是Concurrent Insert(并发插入),MyISAM 存储引擎有一个控制是否打开Concurrent Insert 功能的参数选项:concurrent_insert,可以设置为0,1 或者2。三个值的具体说明如下:

  • set global concurrent_insert=2(always),无论MyISAM 存储引擎的表数据文件的中间部分是否存在因为删除数据而留下的空闲空间,都允许在数据文件尾部进行Concurrent Insert;
  • set global  concurrent_insert=1(auto),当MyISAM 存储引擎表数据文件中间不存在空闲空间的时候,可以从文件尾部进行Concurrent Insert;
  • set global  concurrent_insert=0(never),无论MyISAM 存储引擎的表数据文件的中间部分是否存在因为删除数据而留下的空闲空间,都不允许Concurrent Insert。

合理利用读写优先级

  • 如果我们的系统是一个以读为主,而且要优先保证查询性能的话,我们可以通过设置系统参数选项 low_priority_updates=1,如果我们的系统需要有限保证数据写入的性能的话,则可以不用设置low_priority_updates参数;

MySQL优化数据库连接

优化连接池

  • 连接池运行机制
    • MySQL连接器中的连接池,用以提高数据库密集型应用程序的性能和可扩展性,默认启用。MySQL连接器负责管理连接池中的多个连接,自动创建、打开、关闭和破坏连接,多个连接的创建,可满足多客户端的频繁连接,连接的重复使用获得最佳性能。
    • MySQL连接器 每三分钟运行一次后台作业,并从池中删除闲置(未使用)超过三分钟的连接。池清理释放客户端和服务器端的资源。这是因为在客户端每个连接都使用一个Socket,而在服务器端每个连接都使用一个Socket和一个线程。
  • max_connections,MySQL最大并发连接数,默认值是151,最大连接数上限是16384;
    • 经验:实际连接数是最大连接数的 85% 较为合适
  • 设置 max_used_connections 方法:
    • 查询数据库目前设置的最大并发连接数是多少
      SHOW VARIABLES LIKE 'max_connections';
      
    • 查询数据库目前实际连接的并发数是多少
      SHOW STATUS LIKE 'max_used_connections';
      
    • 在MySQL配置文件 /etc/my.cnf 中设置 max_connections=3000,表示修改最大连接数为3000。

      注意:需要重启 MySQL 才能生效。

    • MySQL为每个连接创建缓冲区,所以不应该盲目上调最大连接数。

      如果最大连接数达到了上面设置的 3000,会消耗大约 800M 内存。

  • 其他连接池设置:
      开启连接池: Pooling=true,默认开启
      
      复用时重置连接状态: ConnectionReset=True
      
      保持连接设置: CacheServerProperties=True
      
      连接超时回收(秒): ConnectionLifeTime=300
      
      支持的最大连接数量: Max Pool Size=100
      
      保持最小的连接数量: Min Pool Size=10
    

    优化请求堆栈

  • back_log,存放执行请求的堆栈大小,默认值是50。
    • 该值设置为最大并发连接数的 20%~30% 较为合适
  • 设置 back_log 方法:
    • 在MySQL配置文件 /etc/my.cnf 中,设置 back_log=600
    • 修改后需要重启 MySQL 才能生效。

修改连接超时时间

  • wait-timeout,超时时间,单位是秒,连接默认超时为8小时,连接长期不用不销毁,比较浪费资源。
    • 经验:设置超时时间为 10 分钟 wait-timeout=600

优化内存缓冲池

  • 缓冲池运行机制
    • 在MySQL5.5之前,广泛使用的和默认的存储引擎是MyISAM。MyISAM使用操作系统缓存来缓存数据。InnoDB需要innodb buffer pool中处理缓存,所以非常需要有足够的InnoDB buffer pool空间。
    • 缓冲区分为 热数据区 / 冷数据区,两者空间占比约为 7/3,每区中的数据集依使用频率按顺序依次排列。 当一个新的查询结果出现后,首先考虑存放到冷数据区,当冷数据区的结果集使用达到一定频率,会被改存到热数据区,使用频率最好的数据集会被存放到热区的首位,当然也有热区转到冷区的状况。
  • InnoDB 缓冲池不仅仅是一个缓存,MySQL InnoDB buffer pool 包含四部分:
    • 数据缓存,InnoDB 数据页面;
    • 索引缓存,索引数据;
    • 缓冲数据,脏页(在内存中修改尚未写入到磁盘的数据);
    • 内部结构,如自适应哈希索引,行锁等。
  • innodb_buffer_pool_instances,内存缓冲池。
    • buffer_pool 把需要缓冲的数据 hash 到不同的缓冲池中,这样可以并行的内存读写。通过减少争用不同线程对缓存页面进行读写的争用,将缓冲池划分为多个单独的实例可以提高并发性。
    • MySQL 5.7、MySQL 8.0 下 innodb_buffer_pool_instances 默认为 1,若 MySQL 存在高并发和高负载访问,设置为 1 则会造成大量线程对 buffer_pool 的单实例互斥锁竞争,这样会消耗一定量的性能的。
    • innodb_buffer_pool_instances 建议设置为 cpu核心数
  • innodb_buffer_pool_chunk_size,缓冲池每块大小,默认128M。
    • pool_chunk_size 一般不做改动,使用默认值就可以。
  • innodb_buffer_pool_size,缓冲池的承载总量。
    • innodb_buffer_pool_size 可以缓存索引和行数据,值越大、IO读写就越少;
    • 设置规则:innodb_buffer_pool_size = (innodb_buffer_pool_chunk_size * {N}块 )* innodb_buffer_pool_instances
    • 如果单纯的做数据库服务,该参数可以设置到电脑物理内存的80%
    • 为了更好的配合 pool_instance,pool_size 需要设置为 pool_instance 和 pool_chunk_size 的整数倍,这样可以被 pool_instance 整除,为每个 buffer pool 实例平均分配内存。如果设置的值不是倍数,MySQL会自动将 pool_size 调整为 pool_chunk_size 的倍数。

优化并发线程数

  • innodb_thread_concurrency,代表并发线程数。
    • 默认是0,表示没有设置线程数量的上限。
    • 不是分配给 MySQL 的线程越多越好,线程多反而会损耗cpu性能,导致速度变慢。
    • 经验:并发线程数应该设置为 cpu 核心数的两倍
    • 注意:这个变量特定于Solaris 8和更早的系统,MySQL 5.7.2中删除了这个变量。
  • 设置 innodb_thread_concurrency 方法:
    • 在MySQL配置文件 /etc/my.cnf 中,设置 innodb_thread_concurrency=8
    • 查看cpu型号
      cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
      
    • 查看cpu核心数

      cat /proc/cpuinfo | grep "cores"|uniq
      

      优化线程池

  • 为什么要优化线程池
    • 客户端发起连接到 MySQL Server 后,MySQL Server监听进程监听到新的请求,然后 Sever 会为其分配一个新的 thread去处理此请求。
    • 从建立连接之开始,CPU要给它划分一定的 thread stack,然后进行用户身份认证,建立上下文信息,最后请求完成,关闭连接,同时释放资源。
    • 在高并发的情况下,这个过程将给系统带来巨大的压力,不能保证性能。MySQL服务器的线程数需要在一个合理的范围之内,这样才能保证MySQL服务器健康平稳地运行。
  • 查看线程池的状态:
      mysql> show variables like 'thread%';
      +--------------------+---------------------------+
      | Variable_name      | Value                     |
      +--------------------+---------------------------+
      | thread_cache_size  | 64                        |
      | thread_concurrency | 10                        |
      | thread_handling    | one-thread-per-connection |
      | thread_stack       | 262144                    |
      +--------------------+---------------------------+
    
  • thread_cache_size
    • thread_cache_size,Threads_cached 中存放的最大连接线程数;
    • 在短连接的应用中,Threads_cached 的功效非常明显,因为在应用中数据库的连接和创建是非常频繁的。如果不使用 Threads_cached,那么消耗的资源是非常可观的。 、
    • 在长连接中虽然带来的改善没有短连接的那么明显,但是好处是显而易见的。但并不是越大越好,大了反而浪费资源,这个的确定一般认为和物理内存有一定关系。
    • Mysql默认值为9。
  • 设置 thread_cache_size 方法:

    • 参考下面额对照表,根据物理内存设置对应的 thread_cache_size 数值:、
      1G —> 8
      2G —> 16
      3G —> 32
      >3G —> 64
      
    • 在 mysql 命令行中设置:
      mysql> set global thread_cache_size=64;
      
  • thread_concurrency
    • thread_concurrency 应设为 CPU核数的2倍。 比如有一个双核的CPU,那么thread_concurrency的应该为4。这个变量是针对Solaris系统的,如果设置这个变量的话,mysqld就会调用thr_setconcurrency()。
    • 这个函数使应用程序给同一时间运行的线程系统提供期望的线程数目,但是在5.7以后就已经抛弃了。
    • 设置 thread_concurrency 方法:
      • 在 mysql 命令行中设置:
        mysql> set global thread_concurrency=4;
        
  • thread_handling
    • thread_handling 运用 Thread_Cache 处理连接的方式,从 5.1.19 添加的新特性,有两个值可选 no-threadsone-thread-per-connection
    • no-threads :服务器使用一个线程
    • one-thread-per-connection :服务器为每个客户端请求使用一个线程
  • thread_stack
    • thread_stack 每个连接被创建的时候,mysql分配给它的内存。这个值一般认为默认就可以应用于大部分场景了,除非必要非则不要动它。上面表示是256kb。
  • 查看线程使用情况

     mysql>  show global status like 'Thread%';
     +-------------------+-------+
     | Variable_name     | Value |
     +-------------------+-------+
     | Threads_cached    | 41    |
     | Threads_connected | 53    |
     | Threads_created   | 541   |
     | Threads_running   | 4     |
     +-------------------+-------+
    
  • Threads_cached
    • MySQL里面为了提高客户端请求创建连接过程的性能,提供了一个连接池也就是 Thread_cache 池(大小是thread_cache_size),将空闲的连接线程放在连接池中,而不是立即销毁。
    • 这样的好处就是,当又有一个新的请求的时候,mysql不会立即去创建连接 线程,而是先去 Thread_Cache 中去查找空闲的连接线程,如果存在则直接使用,不存在才创建新的连接线程。Thread_cache 值表示已经被线程缓存池缓存的线程个数。
  • Threads_connected
    • 当前处于连接状态的线程个数,等于 show processlist。
  • Threads_created
    • Threads_created 表示创建过的线程数,如果发现 Threads_created 值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗资源,可以适当增加配置文件中 thread_cache_size 值。
  • Threads_running
    • 处于激活状态的线程的个数,这个一般都是远小于Threads_connected的。