Mysql的性能优化分为五个方面:
一、硬件的优化
从硬件角度讲,服务器的CPU资源、内存资源、磁盘I/O共同决定了MySQL运行的效率和稳定性,任何部分出现资源不足的情况,MySQL服务本身就会出现性能问题,严重时Mysql服务可能不可用。
CPU主要根据业务考虑选择多核的还是高频的,内存尽量覆盖热数据和索引,硬盘包括机械硬盘和ssd硬盘的选择。
二、操作系统的优化
Mysql一款适合在很多操作系统下运行的数据库,生产环境优先选择linux,操作系统优先选择centos7以上版本。centos 7 默认文件系统是xfs,在大多数情况下,xfs的整体的IOPS表现比ext4更好更稳定。
系统参数的优化:
IO调度算法选择deadline/noop,尽量不使用CFQ(完全公平调度)
fs.file-max: 文件句柄数设置为65536
net.core.somaxconn: 每个socket监听的TCP协议连接数上限,默认128,可以设置为65536.
net.core.netdev_max_backlog: 每个网络端口处理数据包的速度比内核处理数据包的速度快时,允许每个队列数据包的最大长度超过这个值就会被系统直接抛弃或者拒绝,建议设置为65536.
net.ipv4.tcp_max_syn_backlog:在建立三次握手过程中,尚未完成三次握手的连接数上限值,所以成为半连接队列长度。当半连接请求超过此参数的设定值时候,连接就会被拒绝,建议设置为65536.
Mysql多实例资源隔离优化:
一台机器上可能安装多个实例,某个实例如果出现慢查询等原因导致CPU、内存、IO使用率过大,会影响所有Mysql实例。可以采用系统资源隔离的方式Cgroups来解决。Cgroups是linux内核提供的一种可以限制多个进程和多个进程所使用资源的控制。可以对CPU、内存、磁盘I/O等资源进行精细化控制。
三、Mysql参数优化
innodb_buffer_pool_size
表示InnoDB类型的 表 和索引的最大缓存 --它不仅仅缓存 索引数据 ,还会缓存 表的数据 。这个值越大,查询的速度就会越快。这个值太大会影响操作系统的性能。
key_buffer_size
索引缓冲区的大小 索引缓冲区是所有的 线程共享 。增加索引缓冲区可以得到更好处理的索引(对所有读和多重写)。 当然,这个值不是越大越好,它的大小取决于内存的大小。 如果这个值太大,就会导致操作系统频繁换页,也会降低系统性能。 对于内存在 4GB 左右的服务器该参数可设置为 256M 或 384M 。
table_cache
同时打开的表的个数,这个值越大,能够同时打开的表的个数越多。 物理内存越大,设置就越大。默认为2402,调到512-1024最佳。 这个值不是越大越好,因为同时打开的表太多会影响操作系统的性能。
query_cache_size
查询缓冲区的大小 可以通过在MySQL控制台观察, 如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况,就要增加Query_cache_size的值; 如果Qcache_hits的值非常大,则表明查询缓冲使用非常频繁,如果该值较小反而会影响效率,那么可以考虑不用查询缓存;Qcache_free_blocks,如果该值非常大,则表明缓冲区中碎片很多。 MySQL8.0之后失效。该参数需要和query_cache_type配合使用。
query_cache_type
值是0时,所有的查询都不使用查询缓存区 但是query_cache_type=0并不会导致MySQL释放query_cache_size所配置的缓存区内存 当query_cache_type=1时,所有的查询都将使用查询缓存区,除非在查询语句中指定SQL_NO_CACHE, 如SELECT SQL_NO_CACHE * FROM tbl_name。 当query_cache_type=2时,只有在查询语句中使用 SQL_CACHE 关键字,查询才会使用查询缓存区。使用查询缓存区可以提高查询的速度,这种方式只适用于修改操作少且经常执行相同的查询操作的情况。
sort_buffer_size
表示每个需要进行排序的线程分配的缓冲区的大小 增加这个参数的值可以提高 ORDER BY 或 GROUP BY 操作的速度。默认数值是2 097 144字节(约2MB)。对于内存在4GB 左右的服务器推荐设置为6-8M,如果有100个连接,那么实际分配的总共排序缓冲区大小为100 × 6 = 600MB
join_buffer_size = 8M
表示联合查询操作所能使用的缓冲区大小 , 和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。
read_buffer_size
表示 每个线程连续扫描时为扫描的每个表分配的缓冲区的大小(字节) 。 当线程从表中连续读取记录时需要用到这个缓冲区。 SET SESSION read_buffer_size=n可以临时设置该参数的值。默认为64K,可以设置为4M。
innodb_flush_log_at_trx_commit
表示 何时将缓冲区的数据写入日志文件 并且将日志文件写入磁盘中。该参数对于innoDB引擎非常重要。该参数有3个值,分别为0、1和2。该参数的默认值为'1'。 值为 0 时,表示 每秒1次 的频率将数据写入日志文件并将日志文件写入磁盘。每个事务的commit并不会触发前面的任何操作。该模式速度最快,但不太安全,mysqld进程的崩溃会导致上一秒钟所有事务数据的丢失。 值为 1 时,表示 每次提交事务时 将数据写入日志文件并将日志文件写入磁盘进行同步。该模式是最安全的,但也是最慢的一种方式。因为每次事务提交或事务外的指令都需要把日志写入(flush)硬盘。 值为 2 时,表示 每次提交事务时 将数据写入日志文件, 每隔1秒 将日志文件写入磁盘。该模式速度较快,也比0安全,只有在操作系统崩溃或者系统断电的情况下,上一秒钟所有事务数据才可能丢失。
innodb_log_buffer_size
这是 InnoDB 存储引擎的 事务日志所使用的缓冲区 。 为了提高性能,也是先将信息写入 Innodb Log Buffer 中,当满足 innodb_flush_log_trx_commit 参数所设置的相应条件(或者日志缓冲区写满)之后,才会将日志写到文件(或者同步到磁盘)中。
max_connections
表示 允许连接到MySQL数据库的最大数量 , 如果状态变量connection_errors_max_connections 不为零,并且一直增长,则说明不断有连接请求因数据库连接数已达到允许最大值而失败,这是可以考虑增大max_connections 的值。在Linux 平台下,性能好的服务器,支持 500-1000 个连接不是难事,需要根据服务器性能进行评估设定。这个连接数 不是越大 越好 ,因为这些连接会浪费内存的资源。过多的连接可能会导致MySQL服务器僵死。
back_log
用于 控制MySQL监听TCP端口时设置的积压请求栈大小 。如果MySql的连接数达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源,将会报错。5.6.6 版本之前默认值为 50 , 之后的版本默认为 50 + (max_connections / 5), 对于Linux系统推荐设置为小于512的整数,但最大不超过900。如果需要数据库在较短的时间内处理大量连接请求, 可以考虑适当增大back_log 的值。
thread_cache_size
线程池缓存线程数量的大小 当客户端断开连接后将当前线程缓存起来,当在接到新的连接请求时快速响应无需创建新的线程 。这尤其对那些使用短连接的应用程序来说可以极大的提高创建连接的效率。 那么为了提高性能可以增大该参数的值。默认为'60',可以设置为120。 可以通过如下几个MySQL状态值来适当调整线程池的大小: mysql> show global status like 'Thread%'; 当 Threads_cached 越来越少,但 Threads_connected 始终不降,且 Threads_created 持续升高,可 适当增加 thread_cache_size 的大小。
wait_timeout
指定一个请求的最大连接时间 。
interactive_timeout
表示服务器在关闭连接前等待行动的秒数。
四、SQL的优化。
慢sql的查询。
执行计划的分析explain。
show profile工具分析资源消耗情况。
索引优化:
- 前缀索引优化
- 覆盖索引优化
- 主键索引最好是自增的
- 防止索引失效
sql查询语句的优化:
- 查询SQL尽量不要使用select *,而是具体到字段
- 避免在where子句中使用or来连接条件
- 使用varchar代替char
- 尽量使用数值代替字符串类型
- 查询尽量避免返回大量的数据
- 使用explain查看SQL语句的执行计划
- 是否使用了索引及其扫描类型
- 优化like语句
- 避免在索引上使用内置函数
- 避免在where子句中使用表达式操作和=后<>操作符
- 去重distinct过滤字段要少
- where中使用默认值代替null
五、架构设计的优化
在高并发和高性能的场景中,MySQL 数据库承受着并发的压力,优化方式可以氛围以下几个部分。
1. 搭建 Mysql 主从集群,单个 Mysql 服务容易单点故障,一旦服务器宕机,将 会导致依赖 Mysql 数据库的应用全部无法响应。 主从集群或者主主集群可以保 证服务的高可用性。
2. 读写分离设计,在读多写少的场景中,通过读写分离的方案,可以避免读写冲突导致的性能影响
3. 引入分库分表机制,通过分库可以降低单个服务器节点的 IO 压力,通过分表的方式可以降低单表数据量,从而提升 sql 查询的效率。
4. 针对热点数据,可以引入更为高效的分布式数据库,比如 Redis、MongoDB 等,他们可以很好的缓解 Mysql 的访问压力,同时还能提升数据检索性能。