本文参考:
马哥视频教程
mysql官方手册
MySQL 参数配置优化详解
MySQL Innodb 存储引擎参数优化 整理
=======================================[ client ]======================================
password
= []
port
服务端口, default:
3306
socket
服务套接字, 程序使用套接字链接比使用
域名:端口
链接要快, 因为这样就不需要协议解析了
=======================================[ mysqld ]======================================
port
= @MYSQL_TCP_PORT@
socket
= @MYSQL_UNIX_ADDR@
datadir
数据存放目录
skip-external-locking
如果是多服务器环境,希望打开external locking特征,则注释掉这一行即可
# skip-external-locking
如果是单服务器环境,则将其禁用即可,使用如下语句
skip-external-locking
skip-networking
不在TCP/IP端口上进行监听.
如果所有的进程都是在同一台服务器连接到本地的mysqld,
这样设置将是增强安全的方法
所有mysqld的连接都是通过Unix sockets 或者命名管道进行的.
注意在windows下如果没有打开命名管道选项而只是用此项
(通过 “enable-named-pipe” 选项) 将会导致mysql服务没有任何作用!
max-connections
最大连接数, 这个就需要结合业务逻辑进行合理设置了, 同样后面的一些配置也是需要结合这个配置数来进行设置的
比如:
sort_buffer_size, read_buffer_size,net_buffer_size, 这些变量都是基于每个链接设定的,比如一个链接共需要消耗8M
内存, 那最大的瞬时内存就会有max-connnections * (sort_buffer_size+read_buffer_size+net_buffer_size)
来分一杯羹了,其中一个连接将被SUPER权限保留作为管理员登录.
max_connect_errors = 30
每个客户端连接最大的错误允许数量,如果达到了此限制.
这个客户端将会被MySQL服务阻止直到执行了”FLUSH HOSTS” 或者服务重启
非法的密码以及其他在链接时的错误会增加此值.
查看 “Aborted_connects” 状态来获取全局计数器.
table_cache = 4096
所有线程所打开表的数量.
增加此值就增加了mysqld所需要的文件描述符的数量
这样你需要确认在[mysqld_safe]中 “open-files-limit” 变量设置打开文件数量允许至少4096
max_allowed_packet = 32M
服务所能处理的请求包的最大大小以及服务所能处理的最大的请求大小(当与大的BLOB字段一起工作时相当必要)
每个连接独立的大小.大小动态增加
binlog_cache_size = 4M
在一个事务中binlog为了记录SQL状态所持有的cache大小
如果你经常使用大的,多声明的事务,你可以增加此值来获取更大的性能.
所有从事务来的状态都将被缓冲在binlog缓冲中然后在提交后一次性写入到binlog中
如果事务比此值大, 会使用磁盘上的临时文件来替代.
此缓冲在每个连接的事务第一次更新状态时被创建
max_heap_table_size = 128M
独立的内存表所允许的最大容量.
此选项为了防止意外创建一个超大的内存表导致永尽所有的内存资源.
sort_buffer_size
排序缓存区, 这个需要结合
EXPLAIN
来手动分析,是否使用了磁盘文件做排序分析:
如果排序字段使用了索引,Filesort
就为No
,否则Yes
, 如果使用了文件排序,那么就要看sort_buffer_size
的大小, 如果够大的话,就不需要磁盘排序, 如果Filesort_on_disk
为Yes
,那么说明sort_buffer_size
需要加大了# Filesort: No Filesort_on_disk: No Merge_passes: 0
# Filesort: Yes Filesort_on_disk: No Merge_passes: 0
# Filesort: Yes Filesort_on_disk: Yes Merge_passes: 1
2. 排序缓冲被用来处理类似ORDER BY以及GROUP BY队列所引起的排序
如果排序后的数据无法放入排序缓冲,
一个用来替代的基于磁盘的合并分类会被使用
查看 “Sort_merge_passes” 状态变量.
在排序发生时由每个线程分配
join_buffer_size = 16M
此缓冲被使用来优化全联合(full JOINs 不带索引的联合).
类似的联合在极大多数情况下有非常糟糕的性能表现,
但是将此值设大能够减轻性能影响.
通过 “Select_full_join” 状态变量查看全联合的数量
当全联合发生时,在每个线程中分配
max_allowed_packet
有时候大的插入和更新会受max_allowed_packet 参数限制,导致写入或者更新失败。
table_open_cache
打开表缓存数 一般推荐设置为和
max_connections
一样即可
thread_cache_size = 16
我们在cache中保留多少线程用于重用
当一个客户端断开连接后,如果cache中的线程还少于thread_cache_size,
则客户端线程被放入cache中.
这可以在你需要大量新连接的时候极大的减少线程创建的开销
(一般来说如果你有好的线程模型的话,这不会有明显的性能提升.)
thread_concurrency = 8
此允许应用程序给予线程系统一个提示在同一时间给予渴望被运行的线程的数量.
此值只对于支持 thread_concurrency() 函数的系统有意义( 例如Sun Solaris).
你可可以尝试使用 [CPU数量]*(2..4) 来作为thread_concurrency的值
query_cache_size = 128M
查询缓冲常被用来缓冲 SELECT 的结果并且在下一次同样查询的时候不再执行直接返回结果.
打开查询缓冲可以极大的提高服务器速度, 如果你有大量的相同的查询并且很少修改表.
查看 “Qcache_lowmem_prunes” 状态变量来检查是否当前值对于你的负载来说是否足够高.
注意: 在你表经常变化的情况下或者如果你的查询原文每次都不同,
查询缓冲也许引起性能下降而不是性能提升.
query_cache_limit = 4M
只有小于此设定值的结果才会被缓冲
此设置用来保护查询缓冲,防止一个极大的结果集将其他所有的查询结果都覆盖.
default_table_type = MYISAM
当创建新表时作为默认使用的表类型,
如果在创建表示没有特别执行表类型,将会使用此值
transaction_isolation = REPEATABLE-READ
设定默认的事务隔离级别.可用的级别如下:
READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE
tmp_table_size = 128M
内部(内存中)临时表的最大大小
如果一个表增长到比此值更大,将会自动转换为基于磁盘的表.
此限制是针对单个表的,而不是总和.
==================================[ MyISAM ]==================================
key_buffer_size
在mysql数据库中,mysql key_buffer_size是对MyISAM表性能影响最大的一个参数,下面就将对mysql Key_buffer_size参数的设置进行详细介绍,供您参考。
下面一台以MyISAM为主要存储引擎服务器的配置:
mysql> show variables like 'key_buffer_size';
+-----------------+------------+
| Variable_name | Value |
+-----------------+------------+
| key_buffer_size | 536870912 |
+-----------------+------------+
分配了512MB内存给mysql key_buffer_size,我们再看一下key_buffer_size的使用情况:
mysql> show global status like 'key_read%';
+------------------------+-------------+
| Variable_name | Value |
+------------------------+-------------+
| Key_read_requests | 27813678764 |
| Key_reads | 6798830 |
+------------------------+-------------+
一共有27813678764个索引读取请求,有6798830个请求在内存中没有找到直接从硬盘读取索引,计算索引未命中缓存的概率:
key_cache_miss_rate = Key_reads / Key_read_requests * 100%
比如上面的数据,key_cache_miss_rate为0.0244%,4000个索引读取请求才有一个直接读硬盘,已经很BT了,key_cache_miss_rate在0.1%以下都很好(每1000个请求有一个直接读硬盘),如果key_cache_miss_rate在0.01%以下的话,key_buffer_size分配的过多,可以适当减少。
MySQL服务器还提供了key_blocks_*参数:
mysql> show global status like 'key_blocks_u%';
+------------------------+-------------+
| Variable_name | Value |
+------------------------+-------------+
| Key_blocks_unused | 0 |
| Key_blocks_used | 413543 |
+------------------------+-------------+
Key_blocks_unused表示未使用的缓存簇(blocks)数,Key_blocks_used表示曾经用到的最大的blocks数,比如这台服务器,所有的缓存都用到了,要么增加key_buffer_size,要么就是过渡索引了,把缓存占满了。比较理想的设置:
Key_blocks_used / (Key_blocks_unused + Key_blocks_used) * 100% ≈ 80%
net_buffer_length
每一个客户端线程都是被关联的,用连接缓冲和结果缓冲, 这两个缓冲开始被设置为net_buffer_length
这个变量指定的大小,但是当需要增大的时候,会自动的上升为max_allowed_packet
变量所指定的大小, 结果缓冲会收缩到net_buffer_length
这个变量指定的大小在之后的每个SQL语句,
这个变量一般不需要去改变它, 但是如果你的内存比较小的话,那么你可以设置为你期望的大小, 但是如果语句超过了这个长度,那么这个连接缓冲会自动的增大,最大值可以设置为1MB
Command-Line Format --net_buffer_length=#
System Variable
Name net_buffer_length
Variable Scope Global, Session
Dynamic Variable Yes
Permitted Values
Type integer
Default 16384
Min Value 1024
Max Value 1048576
read_buffer_size
每个线程对MyIsam
表做顺序扫描的时候会分配一个缓冲区(以字节为单位
)为每个表, 这个变量的值应该是一个4 kb的倍数。如果它被设置的值不是4 kb的倍数,其价值将四舍五入到最近的4 kb的倍数。
用来做MyISAM表全表扫描的缓冲大小.
当全表扫描需要时,在对应线程中分配.
read_rnd_buffer_size
当从MyIsam表读取已经按照某个key排完顺序的记录的时候, 这个记录就从缓冲区加载而不用扫描磁盘了
This variable is used for reads from MyISAM
tables, and, for any storage engine, for Multi-Range Read optimization.
这个值设置的大可以提高很多排序性能, 然而, 这个缓冲池的分配是针对每个客户端的,所以在全局范围内不应该设置这个值过大(你懂得),而应当是在一个需要运行大量查询的[]session|client ]环境中改变这个变量
当在排序之后,从一个已经排序好的序列中读取行时,行数据将从这个缓冲中读取来防止磁盘寻道.
如果你增高此值,可以提高很多ORDER BY的性能.
当需要时由每个线程分配
bulk_insert_buffer_size = 256M
MyISAM 使用特殊的类似树的cache来使得突发插入
(这些插入是,INSERT … SELECT, INSERT … VALUES (…), (…), …, 以及 LOAD DATA
INFILE) 更快. 此变量限制每个进程中缓冲树的字节数.
设置为 0 会关闭此优化.
为了最优化不要将此值设置大于 “key_buffer_size”.
当突发插入被检测到时此缓冲将被分配.
myisam_sort_buffer_size
myisam_max_sort_file_size = 10G
myisam_max_extra_sort_file_size = 10G
=============================[ InnoDB ]==========================================
skip-innodb
如果你的MySQL服务包含InnoDB支持但是并不打算使用的话,
使用此选项会节省内存以及磁盘空间,并且加速某些部分
innodb_buffer_pool_size = 6G
InnoDB使用一个缓冲池来保存索引和原始数据, 不像 MyISAM.
这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少.
在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的80%
不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸.
注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制,
所以不要设置的太高.
这个参数不能动态更改,所以分配需多考虑。分配过大,会使Swap占用过多,致使Mysql的查询特慢。如果你的数据比较小,那么可分配是你的数据大小+10%左右做为这个参数的值。例如:数据大小为50M,那么给这个值分配innodb_buffer_pool_size=64M
innodb_additional_mem_pool_size = 64M
附加的内存池被InnoDB用来保存 metadata 信息
如果InnoDB为此目的需要更多的内存,它会开始从OS这里申请内存.
由于这个操作在大多数现代操作系统上已经足够快, 你一般不需要修改此值.
SHOW INNODB STATUS 命令会显示当先使用的数量.
innodb_data_file_path = ibdata1:10M:autoextend
InnoDB 将数据保存在一个或者多个数据文件中成为表空间.
如果你只有单个逻辑驱动保存你的数据,一个单个的自增文件就足够好了.
其他情况下.每个设备一个文件一般都是个好的选择.
你也可以配置InnoDB来使用裸盘分区 – 请参考手册来获取更多相关内容
innodb_data_home_dir =
设置此选项如果你希望InnoDB表空间文件被保存在其他分区.
默认保存在MySQL的datadir中.
innodb_file_io_threads = 4
用来同步IO操作的IO线程的数量. This value is
此值在Unix下被硬编码为4,但是在Windows磁盘I/O可能在一个大数值下表现的更好.
innodb_force_recovery=1
如果你发现InnoDB表空间损坏, 设置此值为一个非零值可能帮助你导出你的表.
从1开始并且增加此值知道你能够成功的导出表.
innodb_thread_concurrency = 16
在InnoDb核心内的允许线程数量.
最优值依赖于应用程序,硬件以及操作系统的调度方式.
过高的值可能导致线程的互斥颠簸.
innodb_flush_log_at_trx_commit = 1|2
2性能高,1最安全
从官方解释来看,innodb_support_xa的作用是分两类:第一,支持多实例分布式事务(外部xa事务),这个一般在分布式数据库环境中用得较多。第二,支持内部xa事务,说白了也就是说支持binlog与innodb redo log之间数据一致性。今天的重点是讨论第二类内部xa事务。
首先我们需要明白为什么需要保持binlog与redo log之间数据一致性,这里分两个方面来解释:
第一,保证binlog里面存在的事务一定在redo log里面存在,也就是binlog里不会比redo log多事务(可以少,因为redo log里面记录的事务可能有部分没有commit,这些事务最终可能会被rollback)。先来看这样一个场景(后面的场景都是假设binlog开启):在一个AB复制环境下主库crash,然后进行crash recovery,此时如果binlog里面的的事务信息与redo log里面的信息不一致,那么就会出现主库利用redo log进行恢复后,然后binlog部分的内容复制到从库去,然后出现主从数据不一致状态。所以需要保证binlog与redo log两者事务一致性。
第二,保证binlog里面事务顺序与redo log事务顺序一致性。这也是很重要的一点,假设两者记录的事务顺序不一致,那么会出现类似于主库事务执行的顺序是ta, tb, tc,td,但是binlog里面记录的是ta,tc, tb, td,binlog复制到从库后导致主从的数据不一致。当然也由于当初蹩脚的设计导致BGC被打破,这里就不详说了。
为了达到上面说的两点,mysql是怎么来实现的呢?没错,答案是内部xa事务(核心是2pc)。现在mysql内部一个处理流程大概是这样:
1. prepare ,然后将redo log持久化到磁盘
2. 如果前面prepare成功,那么再继续将事务日志持久化到binlog
3. 如果前面成功,那么在redo log里面写上一个commit记录
那么假如在进行着三步时又任何一步失败,crash recovery是怎么进行的呢? 此时会先从redo log将最近一个检查点开始的事务读出来,然后参考binlog里面的事务进行恢复。如果是在1 crash,那么自然整个事务都回滚;如果是在2 crash,那么也会整个事务回滚;如果是在3 crash(仅仅是commit记录没写成功),那么没有关系因为2中已经记录了此次事务的binlog,所以将这个进行commit。所以总结起来就是redo log里凡是prepare成功,但commit失败的事务都会先去binlog查找判断其是否存在(通过XID进行判断,是不是经常在binlog里面看到Xid=xxxx?这就是xa事务id),如果有则将这个事务commit,否则rollback。
在这三个步骤中因为持久化需求每一步都需要fsync,但是如果真的每一步都需要fsync,那么sync_binlog与innodb_flush_log_at_trx_commit两个参数的意义又在哪?这里还没理得很清楚,希望自己以后补上来或是谁帮忙解答一下。
前面已经解释完了通过内部xa事务来保证binlog里记录的事务不会比redo log多(也可以间接的理解为binlog一定只记录提交事务),这么做的原因是为了crash recovery后主从保持一致性。接下来解释目前是怎么来保证binlog与redo log之间顺序一致的。
为什么要保证binlog里事务与redo log里事务顺序一致性原因前面已经解释过。为了保证这一点带来的问题相信了解过BGC的朋友都知道—-臭名昭著的prepare_commit_mutex,没错就是它导致了正常情况下无法实现BGC,原理是什么?在每次进行xa事务时,在prepare阶段事务先拿到一个全局的prepare_commit_mutex, 然后执行前面说的持久化(fsync)redo log与binlog,然后等fsync完了之后再释放prepare_commit_mutex,这样相当于串行化的效果虽然保证了binlog与redo log之间顺序一致性,但是却导致每个事务都需要一个fsync操作,而大家都知道在一次持久化的过程中代价最大的操作就是fsync了,而想write()这些不落地的操作代价相对来说就很小。所以BGC得核心在于很多事务需要的fsync合并成一个fsync去做。
说了这么多就只为了解释innodb_support_xa=1的价值在哪,但是刚才也说了由于xa事务中需要多次fsync,所以开启后会对性能有一定影响。从percona博客上看到06年他们测试时开启后tps下降一半,但是我实际用mysql-5.5.12+sysbench-0.5+10块SAS(raid 10)测试结果性能下面没那么明显。在oltp模式下tps几乎没差别,不过它默认读写比例是4:1,后来换成纯update测试,开始xa事务性能下降也仅仅是5%左右,没有传说中那么大的差别。所以我怀疑可能的原因有两个:第一,现在的mysql性能相对于06有了较大提升;第二,我测试的机器较好(10块SAS盘做raid10),这样即使开启了xa事务,需要较多的fsync,但是由于存储方面能抗住,所以没有体现出太大的劣势。
接下来顺便谈一下innodb_flush_log_at_trx_commit意义以及合理设置。innodb_flush_log_at_trx_commit有0、1、2三个值分别代表不同的使redo log落地策略。0
表示每秒进行一次flush,但是每次事务commit不进行任何操作(每秒调用fsync使数据落地到磁盘,不过这里需要注意如果底层存储有cache,比如raid cache,那么这时也不会真正落地,但是由于一般raid卡都带有备用电源,所以一般都认为此时数据是安全的)。1
代表每次事务提交都会进行flush,这是最安全的模式。2
表示每秒flush,每次事务提交时不flush,而是调用write将redo log buffer里面的redo log刷到os page cache。那现在来比较三种策略的优劣势:1由于每次事务commit都会是redo log落地所以是最安全的,但是由于fsync的次数增多导致性能下降比较厉害。0表示每秒flush,每次事务提交不进行任何操作,所以mysql crash或者os crash时会丢失一秒的事务。2相对于0来说了多了每次事务commit时会有一次write操作,此时数据虽然没有落地到磁盘但是只要没有 os crash,即使mysql crash,那么事务是不会丢失的。2相对于0来说会稍微安全一点点。
所以关于这两个参数,我的建议是主库开始innodb_support_xa=1,从库不开(因为从库一般不会记binlog),数据一致性还是很重要的。而对于innodb_flush_log_at_trx_commit,除非是对数据很重要,不能丢事务,否则我建议设置成2。我看到有些公司设置成0。其实我个人认为都设置成0了就没有多少理由不设置成2,因为2带来的性能损耗是每个事务一个write操作,write操作的开销相对于fsync还是小很多的,但是这点开销换来了即使mysql挂掉事务依然不会丢的好处。
0,1,2的对比
- 当innodb_flush_log_at_trx_commit和sync_binlog 都为 1 时是最安全的,在mysqld 服务崩溃或者服务器主机crash的情况下,binary log 只有可能丢失最多一个语句或者一个事务。但是鱼与熊掌不可兼得,双11 会导致频繁的io操作,因此该模式也是最慢的一种方式。
- 当innodb_flush_log_at_trx_commit设置为0,mysqld进程的崩溃会导致上一秒钟所有事务数据的丢失。
- 当innodb_flush_log_at_trx_commit设置为2,只有在操作系统崩溃或者系统掉电的情况下,上一秒钟所有事务数据才可能丢失。
innodb_support_xa=1
开启支持内部事务, 简单点说就是为了
binglog
和redo log
保持一致 这样在发生crash后,做data recovery 的时候不是导致主从数据不一致的问题
sync_binlog
- 当sync_binlog =N (N>0) ,MySQL 在每写 N次 二进制日志binary log时,会使用fdatasync()函数将它的写二进制日志binary log同步到磁盘中去. 默认值为0, 代表不主动同步到磁盘,子啊这种情况下,服务器依赖操作系统来刷新二进制文件,
1
是最安全同时也是最慢的, 除非使用缓存的raid卡,并带有备份电源.
innodb_log_buffer_size = 16M
用来缓冲日志数据的缓冲区的大小.
当此值快满时, InnoDB将必须刷新数据到磁盘上.
由于基本上每秒都会刷新一次,所以没有必要将此值设置的太大(甚至对于长事务而言)
innodb_fast_shutdown
加速InnoDB的关闭. 这会阻止InnoDB在关闭时做全清除以及插入缓冲合并.
这可能极大增加关机时间, 但是取而代之的是InnoDB可能在下次启动时做这些操作.
innodb_log_file_size = 512M
在日志组中每个日志文件的大小.
你应该设置日志文件总合大小到你缓冲池大小的25%~100%
来避免在日志文件覆写上不必要的缓冲池刷新行为.
不论如何, 请注意一个大的日志文件大小会增加恢复进程所需要的时间.
innodb_log_files_in_group = 3
在日志组中的文件总数.
通常来说2~3是比较好的.
innodb_log_group_home_dir
InnoDB的日志文件所在位置. 默认是MySQL的datadir.
你可以将其指定到一个独立的硬盘上或者一个RAID1卷上来提高其性能
innodb_max_dirty_pages_pct = 90
在InnoDB缓冲池中最大允许的脏页面的比例.
如果达到限额, InnoDB会开始刷新他们防止他们妨碍到干净数据页面.
这是一个软限制,不被保证绝对执行.
innodb_flush_method=O_DSYNC
InnoDB用来刷新日志的方法.
表空间总是使用双重写入刷新方法
默认值是 “fdatasync”, 另一个是 “O_DSYNC”.
innodb_lock_wait_timeout = 120
在被回滚前,一个InnoDB的事务应该等待一个锁被批准多久.
InnoDB在其拥有的锁表中自动检测事务死锁并且回滚事务.
如果你使用 LOCK TABLES 指令, 或者在同样事务中使用除了InnoDB以外的其他事务安全的存储引擎
那么一个死锁可能发生而InnoDB无法注意到.
这种情况下这个timeout值对于解决这种问题就非常有帮助.
注意:
如果启用了autocommit,那么每一个语句statement就会有一次写操作;否则每个事务对应一个写操作。