MySQL性能优化及问题排查详解

902 阅读7分钟

前言

关于MySQL的知识点总结了一个图谱,分享给大家:

MySQL知识点总结.jpg

常用命令

1.show variables查看系统变量

show variables查看的是mysql系统变量,是MySQL系统运行时的参数,如字符集设置、版本信息、默认参数等,除非手动修改,否则运行时一般不会改变;

2.show status

是MySQL服务器运行统计,如打开的表数量、命令计数、qcache计数等。 是系统状态 是动态

操作方式

1.慢查询

通过show variables like '%slow%';

log_show_queries看是否设置开启慢查询

slow_launch_time查看设置慢查询的时间

show global status like '%slow%';查看慢查询的条数

show global variables like 'slow_query_log_file';查看面查询文件存放位置

2.连接数

show variables like 'max_connections';查看设置的最大连接数

show global status like 'Max_used_connections';查看服务器响应的最大连接数

Max_used_connections / max_connections * 100% ≈ 85%

最大连接数占上限连接数的85%左右,如果发现比例在10%以下,MySQL服务器连接数上限设置的过高了。

3.Key_buffer_size命中率

key_buffer_size是对MyISAM表性能影响最大的一个参数,下面一台以MyISAM为主要存储引擎服务器的配置:

mysql> show variables like 'key_buffer_size';

value分配的内存

show global status like 'key_read%';

两个参数

Key_read_requests内存共有多少索引读取请求

Key_reads 请求在内存中没有找到直接从硬盘读取索引

计算未命中缓存的概率:

key_cache_miss_rate = Key_reads / Key_read_requests * 100%

key_cache_miss_rate在0.1%以下都很好(每1000个请求有一个直接读硬盘),如果key_cache_miss_rate在0.01%以下的话,key_buffer_size分配的过多,可以适当减少。

MySQL服务器还提供了key_blocks_*参数:

show global status like ‘key_blocks_u%’;

两个参数

1.Key_blocks_unused 表示未使用的缓存簇(blocks)数

2.Key_blocks_used 表示曾经用到的最大的blocks数

比较理想的设置:Key_blocks_used / (Key_blocks_unused + Key_blocks_used) * 100% ≈ 80%

4.临时表

show global status like 'created_tmp%';

三个参数

Created_tmp_disk_tables 服务器执行语句时,自动创建临时表数量

Created_tmp_files mysql已经创建临时表数量

Created_tmp_tables 如果自动创建临时表大小偏大,就自动基于内存

每次创建临时表,Created_tmp_tables增加,如果是在磁盘上创建临时表,Created_tmp_disk_tables也增加,Created_tmp_files表示MySQL服务创建的临时文件文件数,比较理想的配置是:

Created_tmp_disk_tables / Created_tmp_tables * 100% <= 25%

MySQL服务器对临时表的配置:

show variables where Variable_name in (‘tmp_table_size’, ‘max_heap_table_size’);

max_heap_table_size

tmp_table_size

5.Open Table情况

show global status like 'open%tables%';

两个参数

Open_tables 打开表的数量

Opened_tables 打开过的表数量

如果Opened_tables数量过大,说明配置中 table_cache(5.1.3之后这个值叫做table_open_cache)值可能太小,我们查询一下服务器table_cache值:

mysql> show variables like ‘table_cache’;

比较合适的值为:

Open_tables / Opened_tables * 100% >= 85%

Open_tables / table_cache * 100% <= 95%

6.线程使用情况

show global status like 'Thread%';

四个参数

Threads_cached

Threads_connected

Threads_created

Threads_running

如果我们在MySQL服务器配置文件中设置了thread_cache_size,当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户 而不是销毁(前提是缓存数未达上限)。Threads_created表示创建过的线程数,如果发现Threads_created值过大的话,表明 MySQL服务器一直在创建线程,这也是比较耗资源,可以适当增加配置文件中thread_cache_size值,查询服务器 thread_cache_size配置:

mysql> show variables like ‘thread_cache_size’;

7.查询缓存(query cache)

show global status like 'qcache%';

变量

Qcache_free_blocks:缓存中相邻内存块的个数。数目大说明可能有碎片。FLUSH QUERY CACHE会对缓存中的碎片进行整理,从而得到一个空闲块。

Qcache_free_memory:缓存中的空闲内存。

Qcache_hits:每次查询在缓存中命中时就增大

Qcache_inserts:每次插入一个查询时就增大。命中次数除以插入次数就是不中比率。

Qcache_lowmem_prunes: 缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间来看;如果这个数字在不断增长,就表示可能碎片非常严重,或者内存 很少。(上面的 free_blocks和free_memory可以告诉您属于哪种情况)

Qcache_not_cached:不适合进行缓存的查询的数量,通常是由于这些查询不是 SELECT 语句或者用了now()之类的函数。

Qcache_queries_in_cache:当前缓存的查询(和响应)的数量。

Qcache_total_blocks:缓存中块的数量。

query_cache的配置:

query_cache_limit:超过此大小的查询将不缓存

query_cache_min_res_unit:缓存块的最小大小

query_cache_size:查询缓存大小

query_cache_type:缓存类型,决定缓存什么样的查询,示例中表示不缓存 select sql_no_cache 查询

query_cache_wlock_invalidate:当有其他客户端正在对MyISAM表进行写操作时,如果查询在query cache中,是否返回cache结果还是等写操作完成再读表获取结果。

query_cache_min_res_unit的配置是一柄”双刃剑”,默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据查询,就容易造成内存碎片和浪费。

查询缓存碎片率 = Qcache_free_blocks / Qcache_total_blocks * 100%

如果查询缓存碎片率超过20%,可以用FLUSH QUERY CACHE整理缓存碎片,或者试试减小query_cache_min_res_unit,如果你的查询都是小数据量的话。

查询缓存利用率 = (query_cache_size - Qcache_free_memory) / query_cache_size * 100% 查询缓存利用率在25%以下的话说明query_cache_size设置的过大,可适当减小;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话说明query_cache_size可能有点小,要不就是碎片太多。

查询缓存命中率 = (Qcache_hits - Qcache_inserts) / Qcache_hits * 100%示例服务器 查询缓存碎片率= 20.46%,查询缓存利用率 = 62.26%,查询缓存命中率 = 1.94%,命中率很差,可能写操作比较频繁吧,而且可能有些碎片。

8.排序使用情况

show global status like 'sort%';

±------------------±-----------+ | Variable_name | Value | ±------------------±-----------+ | Sort_merge_passes | 29 | | Sort_range | 37432840 | | Sort_rows | 9178691532 | | Sort_scan | 1860569 | ±------------------±-----------+ Sort_merge_passes 包括两步。MySQL 首先会尝试在内存中做排序,使用的内存大小由系统变量Sort_buffer_size 决定,如果它的大小不够把所有的记录都读到内存中,MySQL 就会把每次在内存中排序的结果存到临时文件中,等MySQL 找到所有记录之后,再把临时文件中的记录做一次排序。这再次排序就会增加 Sort_merge_passes。实际上,MySQL会用另一个临时文件来存再次排序的结果,所以通常会看到 Sort_merge_passes增加的数值是建临时文件数的两倍。因为用到了临时文件,所以速度可能会比较慢,增加 Sort_buffer_size 会减少Sort_merge_passes 和 创建临时文件的次数,但盲目的增加Sort_buffer_size 并不一定能提高速度

9.文件打开数(open_files)

mysql> show global status like 'open_files';

±--------------±------+ | Variable_name | Value | ±--------------±------+ | Open_files | 1410 | ±--------------±------+ mysql> show variables like ‘open_files_limit’; ±-----------------±------+ | Variable_name | Value | ±-----------------±------+ | open_files_limit | 4590 | ±-----------------±------+ 比较合适的设置:Open_files / open_files_limit * 100% <= 75%

10.表锁情况

mysql> show global status like 'table_locks%';

±----------------------±----------+ | Variable_name | Value | ±----------------------±----------+ | Table_locks_immediate | 490206328 | | Table_locks_waited | 2084912 | ±----------------------±----------+

Table_locks_immediate表示立即释放表锁数,Table_locks_waited表示需要等待的表锁数。

如果Table_locks_immediate/Table_locks_waited>5000,最好采用InnoDB引擎,因为InnoDB是行锁而MyISAM是表锁,对于高并发写入的应用InnoDB效果会好些。

示例中的服务器Table_locks_immediate/Table_locks_waited =235,MyISAM就足够了。

11.表扫描情况

mysql> show global status like 'handler_read%';

±----------------------±------------+ | Variable_name | Value | ±----------------------±------------+ | Handler_read_first | 5803750 | | Handler_read_key | 6049319850 | | Handler_read_next | 94440908210 | | Handler_read_prev | 34822001724 | | Handler_read_rnd | 405482605 | | Handler_read_rnd_next | 18912877839 | ±----------------------±------------+ mysql> show global status like ‘com_select’; ±--------------±----------+ | Variable_name | Value | ±--------------±----------+ | Com_select | 222693559 | ±--------------±----------+

计算表扫描率:

表扫描率=Handler_read_rnd_next/Com_select

如果表扫描率超过4000,说明进行了太多表扫描,很有可能索引没有建好,增加read_buffer_size值会有一些好处,但最好不要超过8MB。

12.QPS(每秒查询量)

show global status like 'Questions'//查询的数量

show global status like 'Uptime'//查询当前MySQL本次启动后的运行统计时间将这两个相除得到每秒查询量

TPS(每秒事务量)

TPS = (Com_commit + Com_rollback) / seconds

mysql > show global status like’Com_commit’;

mysql > show global status like’Com_rollback’;

14)Innodb缓存命中率

show status like ‘Innodb_buffer_pool_%’;

其中,Innodb_buffer_pool_read_requests表示read请求的次数,Innodb_buffer_pool_reads表示从物理磁盘中读取数据的请求次数,所以innodb buffer的read命中率就可以这样得到:

(Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads)/ Innodb_buffer_pool_read_requests * 100%。

一般来讲这个命中率不会低于99%,如果低于这个值的话就要考虑加大innodb buffer pool。

另外,Innodb_buffer_pool_pages_total参数表示缓存页面的总数量(一页16k,所以总共8M),Innodb_buffer_pool_pages_data代表有数据的缓存页数,Innodb_buffer_pool_pages_free代表没有使用的缓存页数。如果Innodb_buffer_pool_pages_free偏大的话,证明有很多缓存没有被利用到,这时可以考虑减小缓存,相反Innodb_buffer_pool_pages_data过大就考虑增大缓存。

默认是8M,一般来讲这个值肯定是不够的,大家通常建议设置为系统内存的50%-80%,但也不是越大越好,要根据具体项目具体分析(操作系统留1G左右,mysql连接数*4M,宿主程序缓存nM)。设置方法,修改/etc/my.cnf文件,并添加字段innodb_buffer_pool_size=3G,然后重启mysql服务就ok了。