MySQL优化基本思想
数据库优化一方面是找出系统的瓶颈,提高MySQL数据库的整体性能,而另一方面需要合理的结构设计和参数调整,以提高用户的相应速度,同时还要尽可能的节约系统资源,以便让系统提供更大的负荷。
这里将优化分为三大类:软优化、底层优化、硬优化。软优化一般是操作数据库即可;而底层优化和硬优化则是操作服务器硬件及参数设置。
软优化
1. 定位慢sql语句
- 执行
show full processlist;
查看当前的sql进程 - 执行如下语句,查看自数据库上次启动至今的增删改查统计结果,以确认应用是以插入更新为主,还是查询为主
show global status where variable_name in ('Com_select','Com_insert','Com_update','Com_delete');
- 修改 my.cnf 开启慢查询记录
slow_query_log = 1 #.slow_query_log[={0|1}]选项来启用慢查询日志
long_query_time = 2 #.所有执行时间超过long_query_time秒的SQL语句都会被记录到慢查询日志。
log_output = file #.设置log_output=table的话,则日志结果会记录到名为mysql.slow_log的表中
slow_query_log_file = /data/mysql_3406/slow.log #.慢查询的日志文件
- 执行
show status like 'Slow_queries';
查看慢查询的次数
2. 分析慢sql语句
可以用 EXPLAIN 或 DESCRIBE(简写:DESC) 命令分析一条查询语句的执行信息。
比如执行 explain SELECT * FROM user;
则会显示索引和查询数据读取数据条数等信息
3. 优化子查询
在MySQL中,尽量使用JOIN来代替子查询。因为子查询需要嵌套查询,嵌套查询时会建立一张临时表,临时表的建立和删除都会有较大的系统开销,而连接查询不会创建临时表,因此效率比嵌套子查询高。
4. 合理使用索引
索引是提高数据库查询速度最重要的方法之一,使用索引的三大注意事项包括:
- 使用多列索引必须满足最左匹配
- LIKE关键字匹配'%'开头的字符串,不会使用索引
- OR关键字的两个字段必须都是用了索引,该查询才会使用索引
5. 字段拆分
对于字段较多的表,如果某些字段使用频率较低,此时应当将其分离出来从而形成新的表。
6. 中间表
对于将大量连接查询的表可以创建中间表,从而减少在查询时造成的连接耗时。
7. 增加冗余字段
类似于创建中间表,增加冗余也是为了减少连接查询。
8. 分析表、检查表、优化表
分析表主要是分析表中关键字的分布;检查表主要是检查表中是否存在错误;优化表主要是消除删除或更新造成的表空间浪费。
- 分析表:使用 ANALYZE 关键字,比如
ANALYZE TABLE user;
- 检查表:使用 CHECK 关键字,比如
CHECK TABLE user [option];
- 优化表:使用 OPTIMIZE 关键字,比如
OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;
底层优化
1. 关闭 numa
- 关闭numa,会提升 15% ~ 30% 的 QPS
关于如何关闭numa
- bios级别关闭:在 BIOS 中设置关闭
BIOS:interleave = Disable / Enable
- grub级别关闭:在 grub 中设置
numa=off
- 数据库级别关闭:修改启动参数
numactl --interleave=all mysqld_safe --defaults-file=/etc/my.cnf &
2. 关闭 THP
- 关闭透明大页 THP(Transparent Huge Pages),否则可能会导致内存泄漏swap的使用或内存的严重碎片化
3. 系统层面参数优化
- 更改文件句柄和进程数 65535
- 防火墙与SeLinux
- 文件系统优化,推荐使用xfs文件系统
- 不适用LVM
硬优化
1. 硬件三件套升级
- CPU:配置多核心和频率高的cpu,多核心可以执行多个线程;
- 内存:增加内存,可以减少磁盘I/O时间,从而提高响应速度;
- 硬盘:配置高速磁盘或合理分布磁盘:高速磁盘提高I/O,分布磁盘能提高并行操作的能力;
2. 优化数据库参数
优化数据库参数可以提高资源利用率,从而提高MySQL服务器性能,下面列出性能影响较大的几个参数:
参数名称 | 默认设置 | 推荐设置 | 描述 |
---|---|---|---|
sync_binlog | - | 1 | 刷binlog的方式,0高性能/1高安全/n兼顾性能和安全 |
binlog_cache_size | 32KB | 8M | 基于会话的、所有未提交的二进制日志缓存文件大小 |
innodb_buffer_pool_size | 8MB | 物理内存的70% | innodb保存索引和原始数据的缓冲池大小 |
innodb_log_file_size | - | 1024M | 日志文件的大小,调大可以提高性能,但也会增加故障恢复所需的时间 |
innodb_log_buffer_size | - | 16M | 日志文件所用的内存大小,调大可以提高性能,但意外故障将会丢失更多数据 |
innodb_flush_log_at_trx_commit | 1 | 1 | log buffer刷新到磁盘的方式,1最安全/0性能最好/其他值则折衷 |
innodb_buffer_pool_instances | 8或1 | 8 | 配置多少个缓存池,建议设置为CPU核数,最大64 |
sort_buffer_size | 256K | 2M | 执行排序缓存区大小 |
read_buffer_size | 256K | 2M | 执行查询缓存区大小 |
join_buffer_size | 256K | 2M | 执行联合查询分配缓存区大小 |
key_buffer_size | - | 64M | 索引块的缓冲区大小,只针对mysiam |
query_cache_size | - | 0 | 查询缓冲区大小 |
query_cache_type | - | 0 | 设置query_cache_size的开关,0/1表示禁用/启用缓冲区 |
max_allowed_packet | 4M | 实际情况 | 最大数据集大小,注意会影响到mysqldump |
thread_cache_size | - | 400 | 线程池缓存大小 |
max_connections | 151 | 3000 | 所有用户同时打开的最大连接数 |
max_user_connections | - | 2000 | 每个用户同时打开的最大连接数 |
更多请参考 MySQL 性能调优和优化资源
3. 读写分离 + 分库分表
若数据库压力过大,首先一个问题就是高峰期系统性能可能会降低,因为数据库负载过高对性能会有影响。
另外一个,压力过大把你的数据库给搞挂了怎么办?
所以此时你必须得对系统做分库分表+读写分离,也就是把一个库拆分为多个库,部署在多个数据库服务上,这时作为主库承载写入请求。然后每个主库都挂载至少一个从库,由从库来承载读请求。
4. 缓存集群
数据库其实本身不是用来承载高并发请求的,通常来说,数据库单机每秒承载的并发就在几千的数量级,而且数据库使用的机器都是比较高配置,比较昂贵的机器,成本很高。如果只是通过简单的加机器来提高并发请求,这个做法其实是不对的。
在高并发架构里通常都有缓存这个环节,缓存系统的设计就是为了承载高并发而生。单机承载的并发量都在每秒几万,甚至每秒数十万,对高并发的承载能力比数据库系统要高出一到两个数量级。你完全可以根据系统的业务特性,对那种写少读多的请求,引入缓存集群。
具体来说,就是在写数据库的时候同时写一份数据到缓存集群(比如 redis)里,然后用缓存集群来承载大部分的读请求。这样的话,通过缓存集群,就可以用更少的机器资源承载更高的并发。
结语
一个完整而复杂的高并发系统架构中,一定会包含各种复杂的自研基础架构系统和各种精妙的架构设计,但是总的来说,数据库优化的思想差不多就这些,希望能对大家有所帮助。