大纲
1.内存相关参数优化
(1)缓冲池内存大小配置
(2)配置多个Buffer Pool实例
(3)Chunk(块)大小配置
(4)InnoDB缓存性能评估
(5)Page管理相关参数
(6)Change Buffer相关参数优化
2.日志相关参数优化
(1)日志缓冲区相关参数配置
(2)日志文件参数优化
3.IO线程相关参数优化
(1)查询缓存相关的参数
(2)脏页刷盘相关的参数
(3)LRU链表相关的参数
(4)脏页刷盘相关的参数
1.内存相关参数优化(Buffer Pool参数优化)
(1)缓冲池内存大小配置
(2)配置多个Buffer Pool实例
(3)Chunk(块)大小配置
(4)InnoDB缓存性能评估
(5)Page管理相关参数
(6)Change Buffer相关参数优化
(1)缓冲池内存大小配置
一个大的日志缓冲区允许大量的事务在提交之前不写日志到磁盘,因此如果有很多增删改操作,通过设置该参数可大量减少磁盘IO次数。
专用数据库服务器上,可将缓冲池大小设置为物理内存的60% - 80%。
一.查看缓冲池大小
Buffer Pool的默认大小是128M。
# 134217728 / 1024 / 1024 = 128
mysql> show variables like '%innodb_buffer_pool_size%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| innodb_buffer_pool_size | 134217728 |
+-------------------------+-----------+
二.在线调整InnoDB缓冲池大小
innodb_buffer_pool_size可以动态设置,允许在不重启服务器情况下动态调整缓冲池大小。
mysql> SET GLOBAL innodb_buffer_pool_size = 268435456; -- 256M
Query OK, 0 rows affected (0.10 sec)mysql> show variables like '%innodb_buffer_pool_size%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| innodb_buffer_pool_size | 268435456 |
+-------------------------+-----------+
三.监控在线调整缓冲池的进度
mysql> SHOW STATUS WHERE Variable_name='InnoDB_buffer_pool_resize_status';
+----------------------------------+----------------------------------------------------------------------+
| Variable_name | Value |
+----------------------------------+----------------------------------------------------------------------+
| Innodb_buffer_pool_resize_status | Size did not change (old size = new size = 268435456. Nothing to do. |
+----------------------------------+----------------------------------------------------------------------+
(2)配置多个Buffer Pool实例
当Buffer Pool的大小是GB级别时:可以将一个Buffer Pool分割成几个独立的实例,这样能降低多个线程同时读写缓存页的竞争性而提高并发性。
通过innodb_buffer_pool_instances参数可以调整实例个数。如果有多个实例,则缓存的数据页会随机放置到任意的实例中,且每个实例都有独立的Buffer Pool所有的特性。
Buffer Pool可以存放多个Instance,每个Instance由多个Chunk组成。Instance的数量范围和Chunk的总数量范围分别为1-64,1-1000。
innodb_buffer_pool_instances的默认值是1,最大可调整成64,需要在初始化数据库时完成。
mysql> show variables like 'innodb_buffer_pool_instances';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| innodb_buffer_pool_instances | 1 |
+------------------------------+-------+
(3)Chunk(块)大小配置
增大或减小缓冲池大小时,将以Chunk为单位进行操作,Chunk的大小是由参数innodb_buffer_pool_chunk_size决定的。引入Chunk是为了方便在线修改缓冲池大小,修改时以Chunk为单位拷贝Buffer Pool。
mysql> show variables like 'innodb_buffer_pool_chunk_size';
+-------------------------------+-----------+
| Variable_name | Value |
+-------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 134217728 |
+-------------------------------+-----------+
缓冲池大小innodb_buffer_pool_size:必须始终等于或者是chunk_size * instances的倍数,如果不等于则MySQL会自动调整。
假设innodb_buffer_pool_chunk_size=128M,而且innodb_buffer_pool_instances=16,那么可以计算出:innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances=2G。如果设置innodb_buffer_pool_size=9G,则会被自动调整为2G的倍数10G。
(4)InnoDB缓存性能评估
当前配置的innodb_buffer_pool_size是否合适,可通过分析InnoDB缓冲池的缓存命中率来验证,以下公式可以计算InnoDB Buffer Pool命中率:
命中率 = innodb_buffer_pool_read_requests / (innodb_buffer_pool_read_requests + innodb_buffer_pool_reads) * 100
参数1:innodb_buffer_pool_reads
表示缓冲池无法满足的请求数,要从磁盘读取。
参数2:innodb_buffer_pool_read_requests
表示从缓冲池中读取页的请求数,如果命中率低于90%,则可考虑增加innodb_buffer_pool_size。
mysql> show status like 'innodb_buffer_pool_read%';
+---------------------------------------+-------+
| Variable_name | Value |
+---------------------------------------+-------+
| Innodb_buffer_pool_read_ahead_rnd | 0 |
| Innodb_buffer_pool_read_ahead | 0 |
| Innodb_buffer_pool_read_ahead_evicted | 0 |
| Innodb_buffer_pool_read_requests | 12701 |
| Innodb_buffer_pool_reads | 455 |
+---------------------------------------+-------+-- 此值低于90%,则可以考虑增加innodb_buffer_pool_size;
mysql> select 12701 / (455 + 12701) * 100 ;
+-----------------------------+
| 12701 / (455 + 12701) * 100 |
+-----------------------------+
| 96.5415 |
+-----------------------------+
(5)Page管理相关参数
innodb_page_size只能在初始化MySQL实例之前配置,不能在之后修改。如果没有指定值,则使用默认页面大小初始化实例。
查看Page页的大小(默认16K)如下:
mysql> show variables like '%innodb_page_size%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
查看Page页管理状态的相关参数如下:
mysql> show global status like '%innodb_buffer_pool_pages%';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| Innodb_buffer_pool_pages_data | 515 |
| Innodb_buffer_pool_pages_dirty | 0 |
| Innodb_buffer_pool_pages_flushed | 334 |
| Innodb_buffer_pool_pages_free | 15868 |
| Innodb_buffer_pool_pages_misc | 0 |
| Innodb_buffer_pool_pages_total | 16383 |
+----------------------------------+-------+# pages_data:缓冲池中包含数据的页数,包括脏页和干净页
# pages_dirty:内存中修改但未写入文件的缓冲池数据页数量
# pages_flushed:表示从InnoDB缓冲池中刷新脏页的请求数
# pages_free:显示InnoDB缓冲池中的空闲页面
# pages_misc:用于管理或哈希索引而不能用作普通页的数目
# pages_total:缓存池的页总数目,单位是Page
一.优化建议
innodb_page_size的官方描述:
MySQL5.7增加了对32K和64K页面大小的支持,所以MySQL5.7支持最小4K最大64K的页面大小设置。
默认的16K或更大的页面大小适用于各种工作负载,特别是涉及表扫描的查询和涉及批量更新的DML操作。对于涉及许多小写操作的OLTP工作负载,较小的页面大小可能更有效。
二.Page大小对于行存储的影响
对于4K、8K、16K和32K的页大小,最大行大小略小于页大小的一半。当然,不包括存储在页外的任何可变长度的列。
三.Page大小对于索引的影响
如果在创建MySQL实例时通过指定innodb_page_size选项,将InnoDB页面大小减少到8K或4K,则索引键的最大长度将按比例降低。这是基于16K页面大小的3072字节限制。也就是说,当页面大小为8K时,最大索引键长度为1536字节。当页面大小为4K时,最大索引键长度为768字节。
(6)Change Buffer相关参数优化
Change Buffer是MySQL5.5加入的新特性,Change Buffer是Insert Buffer的加强。Insert Buffer只针对insert有效,Change Buffer对insert、delete、update、purge都有效。
一.配置Change Buffer使用模式
innodb_change_buffering配置参数说明:
mysql> show variables like '%innodb_change_buffering%';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_change_buffering | all |
+-------------------------+-------+| 选项 | 说明 |
| ------- | --------------------------- |
| inserts | 插入缓冲 |
| deletes | 删除标记缓冲 |
| changes | 更新缓冲,由两个缓冲区组成 |
| purges | 缓冲在后台发生的物理删除操作 |
| all | 表示启用上面所有配置(默认) |
| none | 表示不启用任何配置 |
二.配置Change Buffer大小
Change Buffer占用Buffer Pool空间,默认占25%,最大允许占50%。可以根据读写业务量来调整innodb_change_buffer_max_size,在写多读少+更新后数据不会被立即查询的场景,更适合用Change Buffer。
mysql> show variables like 'innodb_change_buffer_max_size';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| innodb_change_buffer_max_size | 25 |
+-------------------------------+-------+
1 row in set (0.00 sec)
三.查看Change Buffer的工作状态
-- 查看Change Buffer的工作状态
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0# size:表示已经合并到辅助索引页的数量
# free list len:表示空闲列表长度
# seg size:表示当前Change Buffer的大小
# merges:表示合并的次数
# merged operations:每个操作合并次数
# insert:表示插入操作
# delete mark:表示删除标记操作
# delete:表示物理删除操作
2.日志相关参数优化
(1)日志缓冲区相关参数配置
(2)日志文件参数优化
(1)日志缓冲区相关参数配置
日志缓冲区的大小,一般默认值16M都够用了。但如果事务中含有BLOB/TEXT等大字段,这个缓冲区会被很快填满会引起额外的IO负载。可以根据情况配置更大的日志缓冲区,从而有效提高InnoDB的效率。
一.通过参数innodb_log_buffer_size查看日志缓冲区大小
mysql> show variables like 'innodb_log_buffer_size';
+------------------------+----------+
| Variable_name | Value |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
二.通过参数innodb_log_files_in_group查看日志组文件个数
日志组根据需要来创建,日志组的成员则需要至少2个,以实现循环写入并作为冗余策略。
mysql> show variables like 'innodb_log_files_in_group';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2 |
+---------------------------+-------+
三.通过参数innodb_log_file_size查看redo日志文件大小
参数innodb_log_file_size用于设定InnoDB日志组中每个日志文件的大小。参数innodb_log_file_size默认48M,参数innodb_log_file_size是一个全局的静态参数,不能动态修改。每组的文件大小不能超过512G,所以每个日志文件的大小不能超过256G。
mysql> show variables like 'innodb_log_file_size';
+----------------------+----------+
| Variable_name | Value |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
(2)日志文件参数优化
首先看日志文件大小设置对性能的影响。
一.设置过小
影响一:参数innodb_log_file_size设置太小,会导致redo log日志文件频繁切换。频繁触发数据库的检查点checkpoint,导致刷新脏页到磁盘的次数增加,从而影响性能。
影响二:处理大事务时,将所有的日志文件写满了,事务内容还没有写完,这样就会导致日志不能切换。
二.设置过大
参数innodb_log_file_size如果设置太大,虽然可以提升IO性能。但是当数据库意外宕机时,二进制日志文件可能会很大,那么恢复的时间就必然很长,而且恢复时间不可控,受多方面因素影响。
三.优化建议
如何设置合适的日志文件大小,根据实际生产的优化经验,一般是计算一段时间内生成的redo log大小。InnoDB的日志文件的大小最少应该承载一个小时的业务日志量,需要估算出当前系统的一小时内产生的日志数量。
步骤1:获取一分钟内的redo log日志数据量
想要估计redo log的大小,就需要抓取一段时间内Log Sequence Number的数据来计算。自系统修改开始,就不断修改页面,不断生成redo日志。为了记录一共生成了多少日志,InnoDB设计了全局变量Log Sequence Number,简称LSN。LSN不是从0开始的,而是从8704字节开始。
-- pager分页工具, 只获取sequence的信息
mysql> pager grep sequence;
PAGER set to 'grep sequence'-- 查询状态,并倒计时一分钟
mysql> show engine innodb status\G select sleep(60);
Log sequence number 5399154
1 row in set (0.00 sec)1 row in set (1 min 0.00 sec)-- 一分时间内所生成的数据量 5406150
mysql> show engine innodb status\G select sleep(60);
Log sequence number 5406150-- 关闭pager
mysql> nopager;
PAGER set to stdout
步骤2:根据一分钟的redo log日志数据量,推算一小时内的日志数据量
select (5406150 - 5399154) / 1024 as kb_per_min;
+------------+
| kb_per_min |
+------------+
| 6.8320 |
+------------+select (5406150 - 5399154) / 1024 * 60 as kb_per_min;
+------------+
| kb_per_min |
+------------+
| 409.9219 |
+------------+
3.IO线程相关参数优化
(1)查询缓存相关的参数
(2)脏页刷盘相关的参数
(3)LRU链表相关的参数
(4)脏页刷盘相关的参数
数据库属于IO密集型的应用程序,其主要职责就是数据的管理及存储工作。从内存中读取一个数据库数据的时间是微秒级别,从一块普通硬盘上读取一个IO的时间是毫秒级别。要优化数据库,IO操作是必须要优化的,尽可能将磁盘IO转化为内存IO。
(1)查询缓存相关的参数
查询缓存Query Cache会保存SQL查询返回的完整结果。当查询命中查询缓存Query Cache时,会跳过解析、优化和执行阶段,立刻返回结果。查询缓存Query Cache会跟踪查询中涉及的每个表,如果这些表发生变化,那么和这些表相关的查询缓存都将失效。
一.查看查询缓存Query Cache是否开启
-- 查询是否支持查询缓存
show variables like 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+-- 查询是否开启查询缓存 默认关闭
show variables like '%query_cache_type%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| query_cache_type | OFF |
+------------------+-------+
二.在my.ini中添加参数开启查询缓存Query Cache
query_cache_size=128M
query_cache_type=1# query_cache_type=0,缓存禁用;
# query_cache_type=1,缓存所有的结果;
# query_cache_type=DENAND,只缓存在select语句中通过SQL_CACHE指定需要缓存的查询;
三.测试能否缓存查询
mysql> show status like '%Qcache%';
+-------------------------+---------+
| Variable_name | Value |
+-------------------------+---------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 1031832 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 1 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+---------+# Qcache_free_blocks:缓存中目前剩余的block数量
# Qcache_free_memory:空闲缓存的大小
# Qcache_hits:命中缓存次数
# Qcache_inserts:未命中然后进行正常查询
# Qcache_lowmem_prunes:查询因内存不足而被移除出查询缓存记录数
# Qcache_not_cached:没有被缓存的查询数量
# Qcache_queries_in_cache:当前缓存中缓存的查询数量
# Qcache_total_blocks:当前缓存的block数量
四.优化建议
开启查询缓存适用于读多写少的场景,如果写比较多,那么更新查询缓存会损耗性能。
查询缓存的开启主要需要两个参数配合:也就是query_cache_size和query_cache_type。如果数据变化不多(写少),一般缓存大小query_cache_size设置为256M,当然也可以通过计算Query Cache的命中率来进行调整:
Qcache_hits / ( Qcache_hits + Qcache_inserts ) * 100
(2)脏页刷盘相关的参数
一.参数innodb_max_dirty_pages_pct的作用
该参数是InnoDB用来设置Buffer Pool中脏页的百分比,默认是75。当脏页数量占比超过该参数设置的值时,InnoDB会启动刷脏页的操作。
-- innodb_max_dirty_pages_pct 参数可以动态调整,最小值为0,最大值为99.99,默认值为75
show variables like 'innodb_max_dirty_pages_pct';
+----------------------------+-----------+
| Variable_name | Value |
+----------------------------+-----------+
| innodb_max_dirty_pages_pct | 75.000000 |
+----------------------------+-----------+
二.优化建议
该参数比例值越大,从内存到磁盘的写入操作就会相对减少,所以该参数比例值越大越能一定程度减少写入操作的磁盘IO。但是如果这个比例值过大,当数据库Crash后重启的时间可能会很长,因为会有大量的事务数据需要从日志文件恢复出来写入数据文件中。最大不建议超90,一般重启恢复的数据如果超1G,启动速度就会变慢。
(3)LRU链表相关的参数
一.两个相关参数的作用
参数innodb_old_blocks_pct是用来确定LRU链表中冷数据区域所占比例,参数innodb_old_blocks_pct默认37,表示冷数据区域默认占用37%。
mysql> show variables like '%innodb_old_blocks_pct%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37 |
+-----------------------+-------+
参数innodb_old_blocks_time是用来控制冷数据区域中Page的转移策略,参数innodb_old_blocks_time默认值是1秒。新的Page页在进入LRU链表时,会先插入到冷数据区域的头部。然后Page需要在冷数据区域中停留innodb_old_blocks_time后,下一次对该Page的访问才会使其移动到热数据区域的头部。
mysql> show variables like '%innodb_old_blocks_time%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000 |
+------------------------+-------+
二.优化建议
在没有大表扫描的情况下,并且数据多为频繁使用的数据时,可以增加innodb_old_blocks_pct的值,减小innodb_old_blocks_time的值,让数据页能够更快和更多的进入的热点数据区。
(4)与脏页刷盘相关的参数
一.两个相关参数的作用
InnoDB1.0.x版本开始提供innodb_io_capacity参数,它的作用在两个方面:
作用1:合并插入缓冲时,每秒合并插入缓冲数量为innodb_io_capacity值的5%,默认200*5%=10。
作用2:从缓冲区刷新脏页时(Checkpoint),每秒刷新脏页数量为innodb_io_capacity的值,默认是200。若用户使用了SSD类的磁盘,或者将几块磁盘做了RAID,即当存储设备拥有更高的IO时,可将innodbio_capacity_max的值调高,更好利用磁盘IO的吞吐量。
mysql> show variables like '%innodb_io_capacity%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_io_capacity | 200 |
| innodb_io_capacity_max | 2000 |
+------------------------+-------+
二.优化建议
在有频繁写入的操作时,可以对该参数进行调整。该参数设置的大小取决于硬盘的IOPS,即每秒的输入输出量(或读写次数),什么样的磁盘配置应该设置innodb_io_capacity参数的值是多少。下面仅供参考,建议通过sysbench或其他基准测试工具对磁盘吞吐量测试。