比较全面的MySQL优化参考(上下篇)
本⽂整理了⼀些MySQL的通⽤优化⽅法,做个简单的总结分享,旨在帮助那些没有专职MySQL DBA的企业做好基本的优化⼯作,⾄于具体的SQL优化,⼤部分通过加适当的索引即可达到效果,更复杂的就需要具体分析了,可以参考本站的⼀些优化案例或者联系我,下⽅有我的联系⽅式。这是上篇。
1、硬件层相关优化
1.1、CPU相关
在服务器的BIOS设置中,可调整下⾯的⼏个配置,⽬的是发挥CPU最⼤性能,或者避免经典的NUMA问题:
1、选择Performance Per Watt Optimized(DAPC)模式,发挥CPU最⼤性能,跑DB这种通常需要⾼运算量的服务就不要考虑节电了;2、关闭C1E和C States等选项,⽬的也是为了提升CPU效率;
3、Memory Frequency(内存频率)选择Maximum Performance(最佳性能);4、内存设置菜单中,启⽤Node Interleaving,避免NUMA问题;
1.2、磁盘I/O相关
下⾯⼏个是按照IOPS性能提升的幅度排序,对于磁盘I/O可优化的⼀些措施:
1、使⽤SSD或者PCIe SSD设备,⾄少获得数百倍甚⾄万倍的IOPS提升;
2、购置阵列卡同时配备CACHE及BBU模块,可明显提升IOPS(主要是指机械盘,SSD或PCIe SSD除外。同时需要定期检查CACHE及BBU模块的健康状况, 确保意外时不⾄于丢失数据);
3、有阵列卡时,设置阵列写策略为WB,甚⾄FORCE WB(若有双电保护,或对数据安全性要求不是特别⾼的话),严禁使⽤WT策略。并且关闭阵列预读策略, 基本上是鸡肋,⽤处不⼤;
4、尽可能选⽤RAID-10,⽽⾮RAID-5;
5、使⽤机械盘的话,尽可能选择⾼转速的,例如选⽤15KRPM,⽽不是7.2KRPM的盘,不差⼏个钱的;
2、系统层相关优化
2.1、⽂件系统层优化
在⽂件系统层,下⾯⼏个措施可明显提升IOPS性能:
1、使⽤deadline/noop这两种I/O调度器,千万别⽤cfq(它不适合跑DB类服务);
2、使⽤xfs⽂件系统,千万别⽤ext3;ext4勉强可⽤,但业务量很⼤的话,则⼀定要⽤xfs;
3、⽂件系统mount参数中增加:noatime, nodiratime, nobarrier⼏个选项(nobarrier是xfs⽂件系统特有的);
2.2、其他内核参数优化
针对关键内核参数设定合适的值,⽬的是为了减少swap的倾向,并且让内存和磁盘I/O不会出现⼤幅波动,导致瞬间波峰负载:
1、将vm.swappiness设置为5-10左右即可,甚⾄设置为0(RHEL 7以上则慎重设置为0,除⾮你允许OOM kill发⽣),以降低使⽤SWAP的机会;2、将vm.dirty_background_ratio设置为5-10,将vm.dirty_ratio设置为它的两倍左右,以确保能持续将脏数据刷新到磁盘,避免瞬间I/O写, 产⽣严重等待(和MySQL中的innodb_max_dirty_pages_pct类似);
3、将net.ipv4.tcp_tw_recycle、net.ipv4.tcp_tw_reuse都设置为1,减少TIME_WAIT,提⾼TCP效率;
4、⾄于⽹传的read_ahead_kb、nr_requests这两个参数,我经过测试后,发现对读写混合为主的OLTP环境影响并不⼤(应该是对读敏感的场景更有效果), 不过没准是我测试⽅法有问题,可⾃⾏斟酌是否调整;
3、MySQL层相关优化
3.1、关于版本选择
官⽅版本我们称为ORACLE MySQL,这个没什么好说的,相信绝⼤多数⼈会选择它。
我个⼈强烈建议选择Percona分⽀版本,它是⼀个相对⽐较成熟的、优秀的MySQL分⽀版本,在性能提升、可靠性、管理型⽅⾯做了不少改善。它 和官⽅ORACLE MySQL版本基本完全兼容,并且性能⼤约有20%以上的提升,因此我优先推荐它,我⾃⼰也从2008年⼀直以它为主。
另⼀个重要的分⽀版本是MariaDB,说MariaDB是分⽀版本其实已经不太合适了,因为它的⽬标是取代ORACLE MySQL。它主要在原来的MySQL Server层做了⼤量的源码级改进,也是⼀个⾮常可靠的、优秀的分⽀版本。但也由此产⽣了以GTID为代表的和官⽅版本⽆法兼容的新特性(MySQL 5.7开始,也⽀持GTID模式在线动态开启或关闭了),也考虑到绝⼤多数⼈还是会跟着官⽅版本⾛,因此没优先推荐MariaDB。
3.2、关于最重要的参数选项调整建议
建议调整下⾯⼏个关键参数以获得较好的性能(可使⽤本站提供的⽣成配置⽂件模板):
1、选择Percona或MariaDB版本的话,强烈建议启⽤thread pool特性,可使得在⾼并发的情况下,性能不会发⽣⼤幅下降。此外,还有extra_port功能, ⾮常实⽤,关键时刻能救命的。还有另外⼀个重要特⾊是 QUERY_RESPONSE_TIME 功能,也能使我们对整体的SQL响应时间分布有直观感受;
2、设置default-storage-engine=InnoDB,也就是默认采⽤InnoDB引擎,强烈建议不要再使⽤MyISAM引擎了,InnoDB引擎绝对可以满⾜99%以上的业务场景;3、调整innodb_buffer_pool_size⼤⼩,如果是单实例且绝⼤多数是InnoDB引擎表的话,可考虑设置为物理内存的50% ~ 70%左右;
4、根据实际需要设置innodb_flush_log_at_trx_commit、sync_binlog的值。如果要求数据不能丢失,那么两个都设为1。如果允许丢失⼀点数据,
则可分别设为2和10。⽽如果完全不⽤care数据是否丢失的话(例如在slave上,反正⼤不了重做⼀次),则可都设为0。这三种设置值导致数据库的性能受到 影响程度分别是:⾼、中、低,也就是第⼀个会另数据库最慢,最后⼀个则相反;
5、设置innodb_file_per_table = 1,使⽤独⽴表空间,我实在是想不出来⽤共享表空间有什么好处了;
6、设置innodb_data_file_path = ibdata1:1G:autoextend,千万不要⽤默认的10M,否则在有⾼并发事务时,会受到不⼩的影响;7、设置innodb_log_file_size=256M,设置innodb_log_files_in_group=2,基本可满⾜90%以上的场景;
8、设置long_query_time = 1,⽽在5.5版本以上,已经可以设置为⼩于1了,建议设置为0.05(50毫秒),记录那些执⾏较慢的SQL,⽤于后续的分析排查;9、根据业务实际需要,适当调整max_connection(最⼤连接数)、max_connection_error(最⼤错误数,建议设置为10万以上,⽽open_files_limit、 innodb_open_files、table_open_cache、table_definition_cache这⼏个参数则可设为约10倍于max_connection的⼤⼩;
10、常见的误区是把tmp_table_size和max_heap_table_size设置的⽐较⼤,曾经见过设置为1G的,这2个选项是每个连接会话都会分配的,因此不要设置过⼤, 否则容易导致OOM发⽣;其他的⼀些连接会话级选项例如:sort_buffer_size、join_buffer_size、read_buffer_size、read_rnd_buffer_size等, 也需要注意不能设置过⼤;
11、由于已经建议不再使⽤MyISAM引擎了,因此可以把key_buffer_size设置为32M左右,并且强烈建议关闭query cache功能;
3.3、关于Schema设计规范及SQL使⽤建议
下⾯列举了⼏个常见有助于提升MySQL效率的Schema设计规范及SQL使⽤建议:
1、所有的InnoDB表都设计⼀个⽆业务⽤途的⾃增列做主键,对于绝⼤多数场景都是如此,真正纯只读⽤InnoDB表的并不多,真如此的话还不如⽤TokuDB来得划算;2、字段长度满⾜需求前提下,尽可能选择长度⼩的。此外,字段属性尽量都加上NOT NULL约束,可⼀定程度提⾼性能;
3、尽可能不使⽤TEXT/BLOB类型,确实需要的话,建议拆分到⼦表中,不要和主表放在⼀起,避免SELECT * 的时候读性能太差。4、读取数据时,只选取所需要的列,不要每次都SELECT *,避免产⽣严重的随机读问题,尤其是读到⼀些TEXT/BLOB列;
5、对⼀个VARCHAR(N)列创建索引时,通常取其50%(甚⾄更⼩)左右长度创建前缀索引就⾜以满⾜80%以上的查询需求了,没必要创建整列的全长度索引;6、通常情况下,⼦查询的性能⽐较差,建议改造成JOIN写法;7、多表联接查询时,关联字段类型尽量⼀致,并且都要有索引;
8、多表连接查询时,把结果集⼩的表(注意,这⾥是指过滤后的结果集,不⼀定是全表数据量⼩的)作为驱动表;9、多表联接并且有排序时,排序字段必须是驱动表⾥的,否则排序列⽆法⽤到索引;
10、多⽤复合索引,少⽤多个独⽴索引,尤其是⼀些基数(Cardinality)太⼩(⽐如说,该列的唯⼀值总数少于255)的列就不要创建独⽴索引了;11、类似分页功能的SQL,建议先⽤主键关联,然后返回结果集,效率会⾼很多;
3.3、其他建议
关于MySQL的管理维护的其他建议有:
1、通常地,单表物理⼤⼩不超过10GB,单表⾏数不超过1亿条,⾏平均长度不超过8KB,如果机器性能⾜够,这些数据量MySQL是完全能处理的过来的, 不⽤担⼼性能问题,这么建议主要是考虑ONLINE DDL的代价较⾼;
2、不⽤太担⼼mysqld进程占⽤太多内存,只要不发⽣OOM kill和⽤到⼤量的SWAP都还好;
3、在以往,单机上跑多实例的⽬的是能最⼤化利⽤计算资源,如果单实例已经能耗尽⼤部分计算资源的话,就没必要再跑多实例了;4、定期使⽤pt-duplicate-key-checker检查并删除重复的索引。定期使⽤pt-index-usage⼯具检查并删除使⽤频率很低的索引;
5、定期采集slow query log,⽤pt-query-digest⼯具进⾏分析,可结合Anemometer系统进⾏slow query管理以便分析slow query并进⾏后续优化⼯作;6、可使⽤pt-kill杀掉超长时间的SQL请求,Percona版本中有个选项 innodb_kill_idle_transaction 也可实现该功能;7、使⽤pt-online-schema-change来完成⼤表的ONLINE DDL需求;
8、定期使⽤pt-table-checksum、pt-table-sync来检查并修复mysql主从复制的数据差异;
写在最后:这次的优化参考,⼤部分情况下我都介绍了适⽤的场景,如果你的应⽤场景和本⽂描述的不太⼀样,那么建议根据实际情况进⾏调整,⽽不是⽣搬硬套。欢迎质疑拍砖,但拒绝不经过⼤脑的习惯性抵制。
因篇幅问题不能全部显示,请点此查看更多更全内容