搞定MySQL性能调优

|-- 服务器硬件的优化
|-- MySQL数据库配置优化
|-- CentOS系统针对mysql的参数优化
    |-- 内核相关参数(/etc/sysctl.conf)
    |-- 增加资源限制(/etc/security/limit.conf)
    |-- 磁盘调度策略
|-- MySQL的参数配置
|-- MySQL表结构与SQL优化
    |-- 索引优化规则
        |-- 1.使用最左前缀规则
        |-- 2.模糊查询不能利用索引(like '%XX'或者like '%XX%')
        |-- 3.不要过多创建索引
        |-- 4.索引长度尽量短
        |-- 5.索引更新不能频繁
        |-- 6.索引列不能参与计算
    |-- 查询时的优化
        |-- 小表驱动大表
        |-- 避免全表扫描
        |-- 避免mysql放弃索引查询
        |-- 使用覆盖索引,少使用select*
        |-- order by的索引生效
        |-- 不正确的使用导致索引失效
        |-- for update锁表
    |-- 其他优化
        |-- 开启慢查询
        |-- 实时获取有性能问题的SQL
        |-- 垂直分割
        |-- 拆分执行时间长的DELETE或INSERT语句
|-- 好书推荐
    |-- 高性能MySQL
    |-- 阿里巴巴Java开发手册

服务器硬件的优化

提升硬件设备,例如选择尽量高频率的内存(频率不能高于主板的支持)、提升网络带宽、使用SSD高速磁盘、提升CPU性能等。

CPU的选择:

  • 对于数据库并发比较高的场景,CPU的数量比频率重要。
  • 对于CPU密集型场景和频繁执行复杂SQL的场景,CPU的频率越高越好。

MySQL数据库配置优化

  • 表示缓冲池字节大小。
    推荐值为物理内存的50%~80%。
    innodb_buffer_pool_size

  • 用来控制redo log刷新到磁盘的策略。
    innodb_flush_log_at_trx_commit=1

  • 每提交1次事务同步写到磁盘中,可以设置为n。
    sync_binlog=1

  • 脏页占innodb_buffer_pool_size的比例时,触发刷脏页到磁盘。 推荐值为25%~50%。
    innodb_max_dirty_pages_pct=30

  • 后台进程最大IO性能指标。
    默认200,如果SSD,调整为5000~20000
    innodb_io_capacity=200

  • 指定innodb共享表空间文件的大小。
    innodb_data_file_path

  • 慢查询日志的阈值设置,单位秒。
    long_qurey_time=0.3

  • mysql复制的形式,row为MySQL8.0的默认形式。
    binlog_format=row

  • 调高该参数则应降低interactive_timeout、wait_timeout的值。
    max_connections=200

  • 过大,实例恢复时间长;过小,造成日志切换频繁。
    innodb_log_file_size

  • 全量日志建议关闭。
    默认关闭。
    general_log=0

内核相关参数(/etc/sysctl.conf)

以下参数可以直接放到sysctl.conf文件的末尾。

1.增加监听队列上限:

net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535

2.加快TCP连接的回收:

net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1

3.TCP连接接收和发送缓冲区大小的默认值和最大值:

net.core.wmem_default = 87380
net.core.wmem_max = 16777216
net.core.rmem_default = 87380
net.core.rmem_max = 16777216

4.减少失效连接所占用的TCP资源的数量,加快资源回收的效率:

net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

5.单个共享内存段的最大值:

kernel.shmmax = 4294967295

  1. 这个参数应该设置的足够大,以便能在一个共享内存段下容纳整个的Innodb缓冲池的大小。
  2. 这个值的大小对于64位linux系统,可取的最大值为(物理内存值-1)byte,建议值为大于物理内存的一半,一般取值大于Innodb缓冲池的大小即可。

增加资源限制(/etc/security/limit.conf)

打开文件数的限制(以下参数可以直接放到limit.conf文件的末尾):

* soft nofile 65535
* hard nofile 65535

*:表示对所有用户有效
soft:表示当前系统生效的设置(soft不能大于hard )
hard:表明系统中所能设定的最大值
nofile:表示所限制的资源是打开文件的最大数目
65535:限制的数量

以上两行配置将可打开的文件数量增加到65535个,以保证可以打开足够多的文件句柄。

注意:这个文件的修改需要重启系统才能生效。

磁盘调度策略

1.cfq (完全公平队列策略,Linux2.6.18之后内核的系统默认策略)

该模式按进程创建多个队列,各个进程发来的IO请求会被cfq以轮循方式处理,对每个IO请求都是公平的。该策略适合离散读的应用。

2.deadline (截止时间调度策略)

deadline,包含读和写两个队列,确保在一个截止时间内服务请求(截止时间是可调整的),而默认读期限短于写期限。这样就防止了写操作因为不能被读取而饿死的现象,deadline对数据库类应用是最好的选择。

3.noop (电梯式调度策略)

noop只实现一个简单的FIFO队列,倾向饿死读而利于写,因此noop对于闪存设备、RAM及嵌入式系统是最好的选择。

4.anticipatory (预料I/O调度策略)

本质上与deadline策略一样,但在最后一次读操作之后,要等待6ms,才能继续进行对其它I/O请求进行调度。它会在每个6ms中插入新的I/O操作,合并写入流,用写入延时换取最大的写入吞吐量。anticipatory适合于写入较多的环境,比如文件服务器。该策略对数据库环境表现很差。

查看调度策略的方法:

cat /sys/block/devname/queue/scheduler

修改调度策略的方法:

echo <schedulername> > /sys/block/devname/queue/scheduler


MySQL表结构与SQL优化:

1.使用最左前缀规则

2.模糊查询不能利用索引(like '%XX'或者like '%XX%')

3.不要过多创建索引

过多的索引会占用更多的空间,而且每次增、删、改操作都会重建索引。

在一般的互联网场景中,查询语句的执行次数远远大于增删改语句的执行次数,所以重建索引的开销可以忽略不计。但在大数据量导入时,可以考虑先删除索引,批量插入数据,然后添加索引

4.索引长度尽量短

短索引可以节省索引空间,使查找的速度得到提升,同时内存中也可以装载更多的索引键值。

太长的列,可以选择建立前缀索引

5.索引更新不能频繁

更新非常频繁的数据不适宜建索引,因为维护索引的成本。

6.索引列不能参与计算

不要在索引列上做任何的操作,包括计算、函数、自动或者手动类型的转换,这样都会导致索引失效。

比如,where from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成where create_time = unix_timestamp(’2014-05-29’)。

查询时的优化

小表驱动大表

多表关联

第一张表是全表索引(要以此关联其他表),其余表的查询类型type为range(索引区间获得),也就是6 * 1 * 1,共遍历查询6次即可;

建议使用left join时,以小表关联大表,因为使用join的话,第一张表是必须全扫描的,以少关联多就可以减少这个扫描次数.

这里所说的表的type,指的是explain执行计划中的结果字段。详情点击查看,explain的属性详解与提速百倍的优化示例

避免mysql放弃索引查询

如果mysql估计使用全表扫描要比使用索引快,则不使用索引。(最典型的场景就是数据量少的时候)

使用覆盖索引,少使用select*

需要用到什么数据就查询什么数据,这样可以减少网络的传输和mysql的全表扫描。

尽量使用覆盖索引,比如索引为name,age,address的组合索引,那么尽量覆盖这三个字段之中的值,mysql将会直接在索引上取值(using index),并且返回值不包含不是索引的字段。

order by的索引生效

order by排序应该遵循最佳左前缀查询,如果是使用多个索引字段进行排序,那么排序的规则必须相同(同是升序或者降序),否则索引同样会失效。

其他优化

开启慢查询

开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,更好的优化数据库系统的性能。

以后单独的博客进行详细的讲解

实时获取有性能问题的SQL

利用information_schema数据库的processlist表,实时查看执行时间过长的线程,定位需要优化的SQL。

例如下面的SQL的作用是查看正在执行的线程,并按Time倒排序,查看执行时间过长的线程。

select * from information_schema.processlist where Command != 'Sleep' order by Time desc;

利用information_schema数据库的processlist表,实时查看执行时间过长的线程,定位需要优化的SQL。

例如下面的SQL的作用是查看正在执行的线程,并按Time倒排序,查看执行时间过长的线程。

垂直分割

“垂直分割”是一种把数据库中的表,按列变成几张表的方法。这样可以降低表的复杂度和字段的数目,从而达到优化的目的。

示例一:

在Users表中有一个字段是address,它是可选字段,并且不需要经常读取或是修改。

那么,就可以把它放到另外一张表中,这样会让原表有更好的性能。

示例二:

有一个叫 “last_login”的字段,它会在每次用户登录时被更新,每次更新时会导致该表的查询缓存被清空。

所以,可以把这个字段放到另一个表中。

这样就不会影响对用户ID、用户名、用户角色(假设这几个属性并不频繁修改)的不停地读取了,因为查询缓存会增加很多性能。

参考博客:https://www.jianshu.com/p/fc74e946729b



 

发布了550 篇原创文章 · 获赞 10 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/xiamaocheng/article/details/104478126