MySQL上线后根据status状态进行适当优化

时间:2022-09-20 21:46:03

本文摘自《构建高可用linux服务器第三版》

我们可以用如下命令列出MySQL服务器运行的各种状态值:

mysql> show global status;

我个人喜欢的用法是:

show status like '查询值%';

1.慢查询

有时我们为了定位系统中效率比较低下的Query语句,需要打开慢查询日志,也就是slow query log。

mysql> show variables like '%slow%'; +---------------------------+-----------------------------------+
| Variable_name | Value | +---------------------------+-----------------------------------+
| log_slow_admin_statements | OFF | | log_slow_slave_statements | OFF                               |
| slow_launch_time          | 2                                 |
| slow_query_log            | OFF                               |
| slow_query_log_file | /var/lib/mysql/localhost-slow.log | +---------------------------+-----------------------------------+
5 rows in set (0.01 sec)

mysql> show global status like '%slow%'; +---------------------+-------+
| Variable_name | Value | +---------------------+-------+
| Slow_launch_threads | 0     |
| Slow_queries | 0 | +---------------------+-------+

可以看到我们的慢查询日志还没有打开,我们可以使用如下命令打开:

mysql> set global slow_query_log=1;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%slow%'; +---------------------------+-----------------------------------+
| Variable_name | Value | +---------------------------+-----------------------------------+
| log_slow_admin_statements | OFF | | log_slow_slave_statements | OFF                               |
| slow_launch_time          | 2                                 |
| slow_query_log            | ON                                |
| slow_query_log_file | /var/lib/mysql/localhost-slow.log | +---------------------------+-----------------------------------+
5 rows in set (0.00 sec)

打开慢查询日志可能会对系统性能有一点儿影响,如果你的MySQL是主-从结构,可以考虑打开其中一台从服务器的慢查询日志,这样既可以监控慢查询,对系统性能影响也会很小。

2.连接数

如果经常遇见”MySQL:ERROR 1040: Too many connections”的情况,一种情况是访问量确实很高,mysql服务器抗不住,这个时候就要考虑增加从服务器分散读压力了;
另一种情况是mysql配置文件中max_connections的值过小。

mysql> show variables like 'max_connections'; +-----------------+-------+
| Variable_name | Value | +-----------------+-------+
| max_connections | 151 | +-----------------+-------+
1 row in set (0.00 sec)

这台mysql服务器的最大连接数是151,然后查询一下该服务器响应的最大连接数:

mysql> show global status like 'Max_used_connections'; +----------------------+-------+
| Variable_name | Value | +----------------------+-------+
| Max_used_connections | 100 | +----------------------+-------+
1 row in set (0.00 sec)

没有达到上限,应该不会出现1040错误,比较理想的设置是:Max_used_connections/max_connections *100% 约等于 85%
如果发现比例在10%以下,则说明连接数上线设置的过高了。

3.key_buffer_size

key_buffer_size是设置MyISAM表引擎缓存空间的大小,此参数对MyISAM表性能影响最大

mysql> show variables like 'key_buffer_size'; +-----------------+---------+
| Variable_name | Value | +-----------------+---------+
| key_buffer_size | 8388608 | +-----------------+---------+
1 row in set (0.01 sec)

从上面的配置可以看出,分配了8MB内存可以key_buffer_size,我们再看一下key_buffer_size的使用情况:

mysql> show global status like 'key_read%'; +-------------------+-------+
| Variable_name | Value | +-------------------+-------+
| Key_read_requests | 6     |
| Key_reads | 3 | +-------------------+-------+

一个6个索引读取请求,有3个请求在内存中没有找到,直接从硬盘读取索引,计算索引未命中缓存的概率:

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分配过多。
我们此案明显是分配太少了,需要加大。

4.临时表

当执行语句时,关于已经被创造了的隐含临时表的数量,我们可以用如下命令查知其具体情况:

mysql> show global status like 'created_tmp%'; +-------------------------+-------+
| Variable_name | Value | +-------------------------+-------+
| Created_tmp_disk_tables | 0 | | Created_tmp_files | 6 | | Created_tmp_tables | 17 | +-------------------------+-------+

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

Created_tmp_disk_tables / Created_tmp_tables * 100% <= 25%

我们在看一下msyql服务器对临时表的配置:

mysql> show variables where variable_name in ('tmp_table_size','max_heap_table_size'); +---------------------+----------+
| Variable_name | Value | +---------------------+----------+
| max_heap_table_size | 16777216 | | tmp_table_size | 16777216 | +---------------------+----------+

只有16MB以下的临时表才能全部放在内存中,超过就会用到磁盘临时表。

5.open table的情况

opent_tables表示打开表的数量,opened_tables表示打开过的表的数量。我们可以通过如下命令查看其具体情况:

mysql> show global status like 'open_tables%';

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

mysql> show variables like 'table_open_cache'; +------------------+-------+
| Variable_name | Value | +------------------+-------+
| table_open_cache | 2000 | +------------------+-------+

比较合适的值为:

opent_tables / opened_tables * 100% >= 85%
opent_tables / table_open_cache * 100% <= 95%

6.进程使用情况

如果我们在mysql服务器的配置文件中设置了thread_cache_size,当客户端断开之时,服务器处理此客户端请求的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。
threads_created表示创建过的线程数,我们可以用如下命令查看:

mysql> show global status like 'Thread%'; +-------------------+-------+
| Variable_name | Value | +-------------------+-------+
| Threads_cached | 0 | | Threads_connected | 1     |
| Threads_created | 1 | | Threads_running   | 1     |
+-------------------+-------+

如果发现Threads_created的值过大,表明mysql服务器一直在创建线程,这也是比较耗资源的,可以适当增大配置文件中 thread_cache_size的值:

mysql> show variables like 'thread_cache_size'; +-------------------+-------+
| Variable_name | Value | +-------------------+-------+
| thread_cache_size | 9 | +-------------------+-------+

7.查询缓存

主要涉及到2个参数,query_cache_size用于设置msyql的查询缓存大小, query_cache_type用于设置使用查询缓存的类型,可以用如下命令查看其具体情况:

mysql> show global 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       | 4       |
| Qcache_queries_in_cache | 0 | | Qcache_total_blocks | 1 | +-------------------------+---------+

Qcache_free_blocks:缓存中相邻内存块的个数。数目大说明可能有碎片,FLUSH QUERY CACHE会对缓存中的碎片进行整理。
Qcache_free_memory:缓存中空闲内存
Qcache_hits:多少次命中。通过这个参数可以查看query cache的基本效果
Qcache_inserts:每次插入一个查询时就增大。命中次数除以插入次数就是未命中率
Qcache_lowmem_prunes:多少条query因为内存不足而被清除除query cache。通过Qcache_lowmem_prunes和Qcache_free_memory相互结合,能够更清楚地的了解到系统中的query cache的内存大小是否真的足够,是否非常频繁地出现因为内存不足而有query被换出的情况。
Qcache_not_cached:不适合进行缓存的查询数量,通常是由于这些查询不是SELECT语句或用了now()之类的函数。
Qcache_queries_in_cache:当前缓存的查询(和响应)数量
Qcache_total_blocks:缓存中块的数量

我们再查询一下服务器上关于query_cache的配置:

mysql> show variables like 'query_cache%'; +------------------------------+---------+
| Variable_name | Value | +------------------------------+---------+
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 1048576 |
| query_cache_type             | OFF     |
| query_cache_wlock_invalidate | OFF | +------------------------------+---------+

各字段的解释如下所示:
query_cache_limit:超过此大小的查询将不缓存
query_cache_min_res_unit:缓存块的最小值
query_cache_size:查询缓存大小
query_cache_type:缓存类型,决定缓存什么样的查询
query_cache_wlock_invalidate:表示当有其他客户端正在对MyISAM表进行写操作时,读请求是要等WRITE LOCK释放资源后再查询还是允许直接从query cache中读取结果,默认为OFF(可以直接从query cache中取得结果)

8.排序使用情况

它表示系统中对数据进行排序时所使用的buffer,可以用如下命令查看:

mysql> show global status like 'sort%'; +-------------------+-------+
| Variable_name | Value | +-------------------+-------+
| Sort_merge_passes | 0     |
| Sort_range | 1 | | Sort_rows         | 9     |
| Sort_scan | 6 | +-------------------+-------+

Sort_merge_passes包括如下步骤:MySQL首先会尝试在内存中排序,使用的内存大小由系统变量sort_buffer_size来决定,如果它不够大则把所有的记录都读到内存中,而MySQL则会把每次在内存中的排序的结果存到临时文件中,等MySQL找到所有记录之后,再把临时文件中的记录做一次排序。这次排序就会增加Sort_merge_passes。
实际上,MySQL会用另一个临时文件来存储再次排序的结果,所以我们通常会看到Sort_merge_passes增加的数值是建临时文件数的2倍。因为用到了临时文件,所以速度可能会比较慢,增大sort_buffer_size会减少Sort_merge_passes和创建临时文件的次数,但盲目地增大sort_buffer_size并不一定能提高速度。

9.文件打开数

我们在处理MySQL故障时,发现文件打开数(open_files)大于open_files_limit值时,MySQL数据库就会产生卡住的现象,导致Apache服务器也打不开相应页面,这个问题应该在工作中注意,我们可以用如下命令查看具体情况:

mysql> show global status like 'open_files%'; +---------------+-------+
| Variable_name | Value | +---------------+-------+
| Open_files | 17 | +---------------+-------+
1 row in set (0.00 sec)

mysql> show variables like 'open_files_limit%'; +------------------+-------+
| Variable_name | Value | +------------------+-------+
| open_files_limit | 5000 | +------------------+-------+
1 row in set (0.00 sec)

比较合适的设置是:Open_files / open_files_limit * 100% <= 75%

10.Inodb_buffer_pool_size的合理设置

InnoDB存储引擎的缓存机制和MyISAM的最大区别就在于,InnoDB不仅仅缓存索引,同时还会缓存实际的数据。此参数用来设置InnoDB最主要的buffer的大小,也就是缓存用户表及索引数据的最主要缓存空间,对InnoDB整体性能影响也很大。
无论是MySQL官方手册还是网络上许多人分享的Innodb优化建议,都是简单地建议将此值设置为整个系统物理内存的50%~80%。这种做法其实是不妥的,我们应该根据实际的运用场景来正确设置。

mysql> mysql> show global status like 'innodb_buffer_pool_%'; +---------------------------------------+--------------------------------------------------+
| Variable_name | Value | +---------------------------------------+--------------------------------------------------+
| Innodb_buffer_pool_dump_status        | Dumping of buffer pool not started               |
| Innodb_buffer_pool_load_status        | Buffer pool(s) load completed at 161027 11:42:03 |
| Innodb_buffer_pool_resize_status      |                                                  |
| Innodb_buffer_pool_pages_data         | 1046                                             |
| Innodb_buffer_pool_bytes_data         | 17137664                                         |
| Innodb_buffer_pool_pages_dirty        | 0                                                |
| Innodb_buffer_pool_bytes_dirty        | 0                                                |
| Innodb_buffer_pool_pages_flushed      | 48                                               |
| Innodb_buffer_pool_pages_free         | 7129                                             |
| Innodb_buffer_pool_pages_misc         | 17                                               |
| Innodb_buffer_pool_pages_total        | 8192                                             |
| 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      | 23576                                            |
| Innodb_buffer_pool_reads | 1012 | | Innodb_buffer_pool_wait_free | 0 | | Innodb_buffer_pool_write_requests | 463 | +---------------------------------------+--------------------------------------------------+

计算出InnoDB buffer pool的读命中率:
(Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests
写命中率:
Innodb_buffer_pool_pages_data / Innodb_buffer_pool_pages_total
我们发现这个值有点儿过小,就可以考虑增加Inodb_buffer_pool_size的大小。