这是《高性能 MySQL(第三版)》第三章的读书笔记。

关于服务,常见的问题有:

  • 如何确认服务器是否发挥了最大性能
  • 找出执行慢的语句,为何执行慢
  • 为何在用户端发生间歇性的停顿、卡死

通过性能剖析(profiling)分析服务器的性能并找出花费时间最多的地方,有助于解决上述问题。

1. 性能优化简介

性能通常可以认为就是响应时间(Latency,延迟),而性能优化就是减少响应时间。

要想优化性能,首先需要知道性能的瓶颈在哪里。这就需要用到测试了。

2. 性能测试

2.1 对应用程序进行性能测试

每种语言都有专门的测试程序,对于 PHP,可以使用的有:

  • xhprof:轻量小巧,可在生成环境部署。参考 这里
  • xdebug:检测范围大,开销大,适合测试环境。

2.2 对数据库进行性能测试

2.2.1 分析服务器负载

通过分析服务器负载,定位需要优化的单条查询。

捕获 MySQL 的查询到日志文件

MySQL 中,慢查询日志是开销最低、精度最高的测量查询时间的工具。运行时间超过 long_query_time 值语句会被记录到慢查询日志中。long_query_time 单位是秒,默认值为 10,可以设置为 0 来捕获所有的查询。慢查询日志需要手动开启,开启后会略微影响性能。慢查询日志可以写入文件或数据库,但写入到数据库时会影响性能且时间粒度退化为秒级。

MySQL 中还有另外一种查询日志,叫通用日志,但可用信息太少且资源消耗大,基本不用。

慢查询日志相关参数如下,使用可以参考 这里

  • slow_query_log:是否开启慢查询日志,1 开启,0 关闭。
  • log-slow-queries:旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。默认给一个缺省的文件 host_name-slow.log
  • slow-query-log-file:新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。默认给一个缺省的文件 host_name-slow.log
  • long_query_time :慢查询阈值,当查询时间多于设定的阈值时,记录日志。
  • log_queries_not_using_indexes:未使用索引的查询也被记录到慢查询日志中(可选项)。
  • log_output:日志存储方式。log_output=’FILE’表示将日志存入文件,默认值是’FILE’。log_output=’TABLE’表示将日志存入数据库,这样日志信息就会被写入到 mysql.slow_log 表中。MySQL 数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:log_output=’FILE,TABLE’。日志记录到系统的专用日志表中比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,建议优先记录到文件。

分析查询日志

分析慢查询日志可以使用 MySQL 自带的 mysqldumpslow 工具。要用慢查询日志生成分析报告可以使用 pt-query-digest 工具。

2.2.2 分析单条查询

定位到需要优化的单条查询后,开始优化。

SHOW PROFILE(以被 performance_schema 替代)

都废弃了,别研究了。

–使用前先通过 have_profiling 参数查看当前 MySQL是否支持 profile:–

mysql> select @@have_profiling;
+------------------+
| @@have_profiling |
+------------------+
| YES |
+------------------+
1 row in set, 1 warning (0.01 sec) mysql> show warnings;
+---------+------+---------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------------------+
| Warning | 1287 | '@@have_profiling' is deprecated and will be removed in a future release. |
+---------+------+---------------------------------------------------------------------------+
1 row in set (0.00 sec)

–默认禁用,可以通过服务器变量在会话级别启用:–

mysql> SET profiling = 1;

Performace Schema

参考这里

Performace Schema 是目前 MySQL(5.7 及以上版本)主推的性能测试工具,默认开启。首次安装 MySQL 后,你会发现其默认安装了几个数据库,其中的 performace_schema 就是用于配置 Performace Schema 的。

SHOW STATUS

SHOW STATUS 命令返回一些服务器级别的全局计数器或某个会话级别的计数器。可以显示活动频繁程度,但是无法给出消耗的时间。

mysql> show global status;
+-----------------------------------------------+--------------------------------------------------+
| Variable_name | Value |
+-----------------------------------------------+--------------------------------------------------+
| Aborted_clients | 275 |
| Aborted_connects | 80872 |
| Binlog_cache_disk_use | 0 |
...
| Threads_running | 1 |
| Uptime | 6661773 |
| Uptime_since_flush_status | 6661773 |
| validate_password_dictionary_file_last_parsed | 2018-01-31 15:35:09 |
| validate_password_dictionary_file_words_count | 0 |
+-----------------------------------------------+--------------------------------------------------+
355 rows in set (0.03 sec)

2.3 诊断间歇问题

应用偶尔停顿、数据库间歇性的慢查询的可能原因有:

  • 应用通过接口从运行很慢的外部服务获取数据
  • memcached 中的重要缓存条目过期,导致大量请求落到 MySQL 以重新生成缓存条目
  • DNS 查询偶尔超时
  • 互斥锁争用或内部删除查询缓存的算法效率太低,MySQL 的查询缓存导致服务短暂停顿
  • 并发度超过阈值时,InnoDB 的扩展性限制导致查询计划的优化需要很长时间

解决间歇性问题有常见的套路和工具,定位好问题才能进行之后的操作。

2.3.1 单条查询问题还是服务器问题

SHOW GLOBAL STATUS

SHOW STATUS 或 SHOW SESSION STATUS 显示当前会话级别的信息,SHOW GLOBAL STATUS 显示服务器级别的信息。完整差异可以参考 SHOW GLOBAL STATUS vs SHOW STATUS

以较高的频率执行 SHOW GLOBAL STATUS 命令捕获数据,问题出现时可以通过某些计数器(Threads_running、Threads_connected、Questions、Queries)的“尖刺”和“凹陷”来发现问题。SHOW GLOBAL STATUS 命令的用法简单且执行时不需要特殊权限(登录数据库的用户都可以使用)、对服务器影响小。

下面示例通过 -i1 选项每秒捕捉一次数据,输出给 awk 计算并输出每秒的查询数、Threads_connected、Threads_running:

[root@VM_120_242_centos ~]# mysqladmin -uroot -p ext -i1 | awk '/Queries/{q=$4-qp;qp=$4} /Threads_connected/{tc=$4} /Threads_running/{printf "%d %d %d\n", q, tc, $4}'
Enter password:
1554866 1 1
1 1 1
1 1 1

下面示例通过 -i1 选项每秒捕捉一次数据,通过 -r 选项展示差值,输出给 awk 计算并输出每秒的查询数:

# mysqladmin -uroot -p ext -i1 -r | awk '/Queries/{q=$4} /Threads_connected/{tc=$4} /Threads_running/{printf "%d %d %d\n", q, tc, $4}'
Enter password:
1554856 1 1
1 0 0
1 0 0
1 0 0

SHOW PROCESSLIST

不停的捕获 SHOW PROCESSLIST 的输出,可以观察是否有大量线程处于不正常状态或有不正常特征。例如查询很少会长时间处于“statictics”状态。

示例,通过命令尾部使用 \G 替换分号可以垂直输出结果,通过 sort|uniq|sort 命令可以计算某个列值出现的次数:

[root@VM_120_242_centos ~]# mysql -uroot -p -e 'SHOW PROCESSLIST\G' | grep State: | sort | uniq -c | sort -rn
Enter password:
2 State:
1 State: starting

除了通过命令行外,也可以直接查询 INFORMATION_SCHEMA 数据库中的 PROCESSLIST 表。

使用查询日志

需要开启慢查询日志,并在全局级别设置 long_query_time 为 0,然后重置所有连接以使新的全局设置生效。

好的工具可以帮助诊断问题,否则就要去几百 GB 的日志文件中查找问题。下面示例的一行代码可以根据 MySQL 每秒将当前时间写入日志中的模式统计每秒的查询数量:

awk '/^# Time:/{print $3, $4, c; c=0}/^# User/{c++}' slow-query.log

理解发现的问题

建议刚开始诊断问题时,先使用 SHOW STATUS 和 SHOW PROCESSLIST。这两种方法开销低,且可以通过 shell 或反复查询来收集数据。分析慢查询日志则比较困难。

2.3.2 捕获诊断数据

诊断间歇性问题,需要收集尽可能多的数据。需要两个工具:

  • 触发器,即区分问题的方法
  • 收集诊断数据的工具

诊断触发器

触发器需要避免“误报”和“漏检”。

通常将触发器阈值调整为正常情况的一倍左右。比如 Threads_running 在正常情况下是 10,则触发器的阈值可以设置为 20。对于 Threads_connected 如果正常值为 150,则阈值可以是 300。

另外,还需要设置持续时间。比如 Threads_running 连续 3 秒钟超过 20,则认为是异常情况。可以使用“pt-stalk”工具。

需要收集的数据类型

确定诊断触发器后,可以开启进程收集数据。数据应该尽可能多,包括系统状态、CPU 利用率、磁盘使用率和可用空间、内存利用率、ps 命令的输出采样,以及从 MySQL 获得的信息,包括 SHOW STATUS、SHOW INNODB STATUS、SHOW PROCESSLIST。

Linux 上可用的服务器内部诊断工具有 oprofile、strace(生产环境中使用有风险)。要剖析查询可用 tcpdump。

可以通过 GDB 堆栈跟踪分析等待原因。跟踪时先启动 GDB,然后附加(attach)到 mysqld 进程,将所有线程的堆栈都存储起来。然后利用脚本汇总类似的堆栈信息,再利用 sort|uniq|sort 排序。

解释结果数据

2.3.3 案例

2.4 其他分析工具

2.4.1 USER_STATISTICS 表

INFORMATION_SCHEMA 库中的表,存储了各个数据库的信息及所有活动的统计信息,可以得知哪个数据库的哪个表、哪个索引使用的最频繁。

表索引的信息。SHOW INDEX FROM schemaname.tablename; 命令从这个表获取结果。

mysql> SHOW INDEX FROM szhuizhong.users;
+-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users | 0 | PRIMARY | 1 | UserID | A | 1460 | NULL | NULL | | BTREE | | |
| users | 0 | Account_index | 1 | Account | A | 1460 | NULL | NULL | | BTREE | | |
| users | 1 | CorpID | 1 | FromID | A | 2 | NULL | NULL | YES | BTREE | | |
+-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

5. 总结

要解决问题,首先要搞清楚问题。所有的查询记录都要记录到日志中,然后用 pt-query-digest 工具生成系统级别的剖析报告。

MySQL 服务器性能剖析的更多相关文章

  1. 提升mysql服务器性能(复制原理与拓扑优化)

    原文:提升mysql服务器性能(复制原理与拓扑优化) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/details/9008171 ...

  2. 提升mysql服务器性能(HA MMM MHA MaxScale)

    原文:提升mysql服务器性能(HA MMM MHA MaxScale) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/detai ...

  3. 提升mysql服务器性能(索引与查询优化)

    原文:提升mysql服务器性能(索引与查询优化) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/details/90138407 ...

  4. 提升mysql服务器性能(分库、分片与监控)

    原文:提升mysql服务器性能(分库.分片与监控) 版权声明:皆为本人原创,复制必究 https://blog.csdn.net/m493096871/article/details/90145515 ...

  5. 高性能MySQL(三):服务器性能剖析

    select * from c LEFT JOIN c100w on c.id=c100w.id; -- 联合查询 show PROFILES; -- 查看查询耗时 select * from c; ...

  6. MySQL服务器基准测试

    一.基准测试简介 1.什么是基准测试 数据库的基准测试是对数据库的性能指标进行定量的.可复现的.可对比的测试. 基准测试与压力测试 基准测试可以理解为针对系统的一种压力测试.但基准测试不关心业务逻辑, ...

  7. 11 MySQL之性能优化

    01-优化简介 MySQL数据库优化是多方面的,原则是减少系统瓶颈,减少资源的占用,增加系统的反应速度. 1.通过优化文件系统,提高磁盘I\O的速写速度: 2.通过优化操作系统的调度策略,提高MySQ ...

  8. MySQL 高级性能优化架构 千万级高并发交易一致性系统基础

    一.MySQL体系架构 由图,可以看出MySQL最上层是连接组件.下面服务器是由连接池.管理服务和工具组件.SQL接口.查询解析器.查询优化器.缓存.存储引擎.文件系统组成. 1.连接池 管理.缓冲用 ...

  9. MySQL性能剖析工具(pt-query-digest)【转】

    这个工具同样来自percona-toolkit 该工具集合的其他工具 MySQL Slave异常关机的处理 (pt-slave-restart)  验证MySQL主从一致性(pt-table-chec ...

随机推荐

  1. webpack打包html里的img图片

    对待css里的图片, 因为已经通过引入css文件到js,打包了,可以正常通过module.rules.test检测到,然后正常打包. 但是对于html里的图片, 这个需要安装一个插件html-with ...

  2. 对第一个HelloWorld程序的总结:

    /* 注释的作用 :提高了代码的阅读性:调试程序的重要方法 对第一个程序的总结: 创建:创建一个以.java结尾的文件叫做源文件 编译:(javac 源文件名.java) 会生成一个或多个字节码(.c ...

  3. Can you answer these queries? HDU 4027 线段树

    Can you answer these queries? HDU 4027 线段树 题意 是说有从1到编号的船,每个船都有自己战斗值,然后我方有一个秘密武器,可以使得从一段编号内的船的战斗值变为原来 ...

  4. LLVM思想与功能综述

    llvm似乎还有一个奇怪的优化方法:llvm(low level virtual machine)本身就是一种抽象的.虚拟的计算机架构,其特性介于RISC和CISC之间,llvm会先将代码编译为llv ...

  5. 问题 C: 序列交换

    问题 C: 序列交换 时间限制: 1 Sec  内存限制: 128 MB提交: 914  解决: 48[提交] [状态] [命题人:jsu_admin] 题目描述 给一个 1 到 n 的排列,每次可以 ...

  6. Vue slot-scope的理解(适合初学者)

    百度上已经有很多的关于slot-scope的文章,但我感觉都是那些以前没学好,又回头学的人,他们都使用了.Vue文件,我觉得有点不适合初学者,所以我就写一篇适合初学者的. 先抛例程: <!DOC ...

  7. oracle学习笔记(四) DML数据控制语言和TCL 事务控制语言

    DML 数据管理语言 Data manage language insert, update, delete以及select语句,不过,有人也把select单独出来,作为DQL 数据查询语言 data ...

  8. SpringBoot 利用freemaker生成静态页面

    1. <!-- freemarker模板 --> <dependency> <groupId>org.springframework.boot</groupI ...

  9. Typescript + TSLint + webpack 搭建 Typescript 的开发环境

    (1)初始化项目 新建一个文件夹“client-side”,作为项目根目录,进入这个文件夹: 我们先使用 npm 初始化这个项目: 这时我们看到了在根目录下已经创建了一个 package.json 文 ...

  10. 前端面试题1(HTML篇)

    HTML 语义化 HTML标签的语义化是指:通过使用包含语义的标签(如h1-h6)恰当地表示文档结构 css命名的语义化是指:为html标签添加有意义的class 为什么需要语义化: 去掉样式后页面呈 ...