pt-query-digest用于分析mysql慢查询的工具,可以分析binlog、General log、slowlog,甚至processlist
分析过程是先对查询语句的条件进行参数化,然后对参数化以后的查询进行分组统计,统计出各查询的执行时间、次数、占比等,可以借助分析结果找出问题进行优化。
yum -y install perl-Digest-MD5
yum -y install perl-DBI
yum -y install perl-DBD-MySQL
yum -y install perl-Time-HiRes
yum -y install perl-IO-Socket-SSL
yum -y install perl-TermReadKey
rpm -ivh percona-toolkit-3.5.1-2.el7.x86_64.rpm
pt-query-digest [OPTIONS] [FILES] [DSN]
pt-query-digest --help
变量 | 默认值 | 说明 |
---|---|---|
–ask-pass | FALSE | #连接到MySQL时提示输入密码 |
–attribute-aliases | db/Schema | #属性列表别名等(默认db/schema) |
–attribute-value-limit | 0 | #属性值的限制(默认为0) |
–charset | (No value) | #默认字符集 |
–config | /etc/percona-toolkit/percona-toolkit.conf,/etc/percona-toolkit/pt-query-digest.conf,/root/.percona-toolkit.conf,/root/.pt-query-digest.conf | #逗号分隔的配置文件列表;如果指定,则必须是命令行上的第一个选项 |
–continue-on-error | TRUE | #即使有错误也继续解析 |
–create-history-table | TRUE | #创建–history表(如果不存在)(默认为yes) |
–create-review-table | TRUE | #创建–review表(如果不存在)(默认为yes) |
–daemonize | FALSE | #Fork到后台并从shell分离 |
–database | (No value) | #连接到该数据库 |
–defaults-file | (No value) | #从给定文件读取mysql选项 |
–embedded-attributes | (No value) | #两个Perl正则表达式模式,用于捕获查询中嵌入的伪属性 |
–expected-range | 5,10 | #当数量多于或少于预期时解释项目(默认值为5,10) |
–explain | (No value) | #使用此DSN对示例查询运行EXPLAIN并打印结果 |
–filter | (No value) | #过滤事件 |
–group-by | fingerprint | #要对事件的哪个属性进行分组(默认fingerprint) |
–help | TRUE | #显示帮助并退出 |
–history | (No value) | #在给定表中保存每个查询类的指标。 pt-query-digest将查询指标(查询时间,锁定时间等)保存到此表中,以便您查看查询类如何随时间变化 |
–host | (No value) | #连接到主机 |
–ignore-attributes | arg cmd insert_id ip,port Thread_id timestamp exptime flags key res val server_id offset end_log_pos Xid |
#不要聚合这些属性 |
–inherit-attributes | db,ts | #如果丢失,则从具有属性的最后一个事件继承这些属性(默认db,ts) |
–interval | .1 | #轮询show processlist的频率,以秒为单位(默认为.1) |
–iterations | 1 | #在收集和报告周期中迭代多少次(默认为1) |
–limit | 95%:20 | #将输出限制为给定的百分比或计数(默认为95%:20) |
–log | (No value) | #守护进程时将所有输出打印到此文件 |
–max-hostname-length | 10 | #将报告中的主机名修剪到此长度。 0 =不修剪主机名(默认为10) |
–max-line-length | 74 | #将行修剪到此长度。 0 =不修剪线条(默认74) |
–order-by | Query_time:sum | #按此属性:聚合函数对事件进行排序(默认Query_time:sum) |
–outliers | Query_time:1:10 | #按属性:百分比:计数报告异常值(默认查询时间:1:10) |
–output | report | #如何格式化和打印查询分析结果(默认report) |
–password | (No value) | #连接时使用的密码 |
–pid | (No value) | #创建给定的PID文件 |
–port | (No value) | #用于连接的端口号 |
–preserve-embedded-numbers | FALSE | #查询时保留数据库/表名中的数字 |
–processlist | (No value) | #使用–interval sleep轮询此DSN的进程列表以进行查询 |
–progress | time,30 | #将进度报告打印到STDERR(默认时间30) |
–read-timeout | 0 | #等待的超时时间,等待来自输入的事件; 0表示永远等待(默认值为0)。 可选后缀s =秒,m =分钟,h =小时,d =天; 如果没有后缀,则使用s。 |
–report | TRUE | #打印每个–group-by属性的查询分析报告(默认为yes) |
–report-all | FALSE | #报告所有查询,甚至包括已审核的查询 |
–report-format | rusage,date,hostname,files,header,profile,query_report,prepared | #打印查询分析报告的这些部分 |
–report-histogram | Query_time | #绘制此属性值的分布图(默认Query_time) |
–resume | (No value) | #如果指定,该工具会将最后一个文件偏移(如果有的话)写入给定的文件名 |
–review | (No value) | #保存查询以供以后查看,并且不报告已查看的 |
–run-time | (No value) | #每个迭代要运行多长时间。可选后缀s =秒,m =分钟,h =小时,d =天;如果没有后缀,则使用s。 |
–run-time-mode | clock | #设置–run-time的值所用的值(默认clock) |
–sample | (No value) | #过滤掉每个查询中除前N个事件外的所有事件 |
–set-vars | #在此以逗号分隔的(变量=值对)列表中设置MySQL变量 | |
–show-all | #显示这些属性的所有值 | |
–since | (No value) | #解析仅查询比该值新的查询(自此日期以来解析查询) |
–slave-password | (No value) | #设置用于连接到从的密码 |
–slave-user | (No value) | #设置用于连接到从的用户 |
–socket | (No value) | #用于连接的套接字文件 |
–timeline | FALSE | #显示事件的时间表 |
–type | slowlog | #要解析的输入的类型(默认慢日志) |
–until | (No value) | #仅解析早于此值的查询(直到此日期为止解析查询) |
–user | (No value) | #用于登录的用户(如果不是当前用户) |
–variations | #报告这些属性值的变化数量 | |
–version | FALSE | #显示版本并退出 |
–version-check | TRUE | #检查最新版本的Percona Toolkit,MySQL和其他程序(默认为是) |
–vertical-format | TRUE | #在报告的SQL查询中输出尾随的“ \ G”(默认为是) |
–watch-server | (No value) | #此选项告诉pt-query-digest在解析tcpdump时要监视哪个服务器IP地址和端口(例如“ 10.0.0.1:3306”)(对于–type tcpdump);其他所有服务器均被忽略 |
--create-review-table 当使用--review参数把分析结果输出到表中时,如果没有表就自动创建。
--create-history-table 当使用--history参数把分析结果输出到表中时,如果没有表就自动创建。
--filter 对输入的慢查询按指定条件进行匹配过滤后再进行分析
--limit 限制输出结果百分比或数量,默认值是20,即将最慢的20条语句输出,如果是50%则按总响应时间占比从大到小排序,输出到总和达到50%位置截止。
--host mysql服务器地址
--user mysql用户名
--password mysql用户密码
--history 将分析结果保存到表中,分析结果比较详细,下次再使用--history时,如果存在相同的语句,且查询所在的时间区间和历史表中的不同,则会记录到数据表中,可以通过查询同一CHECKSUM来比较某类型查询的历史变化。
--review 将分析结果保存到表中,这个分析只是对查询条件进行参数化,一个类型的查询一条记录,比较简单。当下次使用--review时,如果存在相同的语句分析,就不会记录到数据表中。
--output 分析结果输出类型,值可以是report(标准分析报告)、slowlog(Mysql slow log)、json、json-anon,一般使用report,以便于阅读。
--since 从什么时间开始分析,值为字符串,可以是指定的某个”yyyy-mm-dd [hh:mm:ss]”格式的时间点,也可以是简单的一个时间值:s(秒)、h(小时)、m(分钟)、d(天),如12h就表示从12小时前开始统计。
--until 截止时间,配合—since可以分析一段时间内的慢查询。
--sample:过滤掉每个查询中除前N个事件外的所有事件
--type: slowlog,genlog,binlog指定分析的日志类型
当使用过滤/分组/排序的时候,需要了解其事件属性,可用于过滤/分组/排序。
event
pt-query-digest处理得到的单元叫事件,这些事件是属性集合,例如查询时间,锁时间等。
得到属性
$ pt-query-digest slow.log --filter 'print Dumper $event' --no-report --sample 1
产生很多带有“ attribute => value”对的输出
$VAR1 = {
Lock_time => '0.000101',
Query_time => '7.967977',
Rows_examined => '1000000',
Rows_sent => '1000000',
Thread_id => '20',
arg => 'select * from emp limit 1000000',
bytes => 31,
cmd => 'Query',
db => 'dbsql',
fingerprint => 'select * from emp limit ?',
host => 'localhost',
ip => '',
pos_in_log => 8768,
timestamp => '1679739655',
ts => '2023-03-25T10:20:55',
user => 'root'
};
$VAR1 = {
Query_time => '7.967977',
Thread_id => '20',
arg => 'select * from emp limit 1000000',
bytes => 31,
cmd => 'Query',
db => 'dbsql',
fingerprint => 'select * from emp limit ?',
pos_in_log => 8768,
ts => '2023-03-25T10:20:55'
};
$VAR1 = {
Query_time => '7.967977',
Thread_id => '20',
arg => 'select * from emp limit 1000000',
bytes => 31,
cmd => 'Query',
db => 'dbsql',
end_log_pos => '289',
error_code => '0',
fingerprint => 'select * from emp limit ?',
offset => '108',
pos_in_log => 8768,
server_id => '111',
timestamp => '1679739655',
ts => '2023-03-25T10:20:55',
};
--filter '($event->{Row_ratio} = $event->{Rows_sent} / ($event->{Rows_examined})) && 1'
# Row ratio 1.00 0.00 1 0.50 1 0.71 0.50
默认情况下按fingerprint分组,并按查询时间的降序排列(最慢的查询排在第一位)。
SELECT name, password FROM user WHERE id='12823';
select name, password from user where id=5;
可以合并当成:
select name, password from user where id=?
--group-by=db,user
# Report grouped by db
...
# Report grouped by user
...
fingerprint:指纹,将查询抽象为规范形式,然后用于将event分组到一个类中。
tables:按表的形式返回报告信息。
distill:超级指纹,将查询分解为对它们执行操作的建议。
只返回指定类型的查询,如返回select的查询:
--filter '$event->{arg} =~ m/^select/i'
--filter '$event->{fingerprint} =~ m/^select/i'
只返回指定用户的查询,如返回hulk用户的查询:
--filter '$event->{user} =~ m/^hulk/i'
--filter '($event->{user} || "") =~ m/^hulk/i'
只返回指定IP的查询,如返回192.168.16.111的查询:
--filter '($event->{host} || $event->{ip} || "") =~ m/^192.168.16.111/i'
只返回指定DB的查询,如返回dbsql DB的查询:
--filter '($event->{db} || "") =~ m/^dbsql/i'
返回指定DB和类型的查询,如返回dbsql DB中的select查询:
--filter '(($event->{db} || "") =~ m/^dbsql/i) && (($event->{fingerprint} || "") =~ m/^select/i)'
order-by:通过指定属性对事件进行排序,默认值:Query_time:sum,也用于–group-by属性。
对于genlog)默认的属性为Query_time:cnt。
#按总的执行时间排序
order-by=Query_time:sum
#按总的执行次数排序
order-by=Query_time:cnt
--history='h=192.168.163.132,u=root,p=root'
用于创建DSN, 例如想将得到的数据存储到表中,则配置DSN。各个选项说明如下:
A:默认字符集
D:连接到MySQL时要使用的默认数据库。
F:从给定文件中读取默认选项。
h:连接到主机的地址。
p:连接使用的密码,如果密码包含逗号,则必须使用反斜杠将其转义。
P:用于连接的端口号。
S:连接的套接字文件。
t:指定--review或--history表名。
u:连接的用户。
slow log:–type=slowlog
$VAR1 = {
Lock_time => '0.000101',
Query_time => '7.967977',
Rows_examined => '1000000',
Rows_sent => '1000000',
Thread_id => '20',
arg => 'select * from emp limit 1000000',
bytes => 31,
cmd => 'Query',
db => 'dbsql',
fingerprint => 'select * from emp limit ?',
host => '192.168.16.111',
ip => '192.168.16.111',
pos_in_log => 8768,
timestamp => '1679739655',
ts => '2023-03-25T10:20:55',
user => 'root'
};
-- 分析消耗的用户CPU时间,系统CPU时间,物理内存占用大小,虚拟内存占用大小
# 150ms user time, 20ms system time, 27.02M rss, 221.53M vsz
-- 分析的当前日期
# Current date: Sun Mar 26 09:49:20 2023
-- 分析的主机名
# Hostname: sdns
-- 分析的文件名
# Files: /data/mysql/my3306/logs/slow.log
-- 分析的整体情况:语句总数量,唯一语句数量,QPS和并发数
# Overall: 40 total, 14 unique, 0.00 QPS, 0.01x concurrency
-- 分析日志的时间范围
# Time range: 2023-03-24T13:55:43 to 2023-03-26T13:47:01
--属性 总计 最小 最大 平均 95% 标准 中等
# Attribute total min max avg 95% stddev median
# ============ ======= ======= ======= ======= ======= ======= =======
-- 执行时间
# Exec time 918s 322us 734s 23s 26s 112s 32ms
-- 锁时间
# Lock time 385ms 0 199ms 10ms 38ms 32ms 268us
-- 发送到客户端的行数
# Rows sent 18.88M 0 7.63M 483.42k 1.86M 1.24M 3.89
-- 扫描行数
# Rows examine 27.62M 0 7.63M 707.19k 2.75M 1.65M 3.89
-- 查询的字节数
# Query size 1.34k 15 123 34.20 80.10 22.23 24.84
/*如果在此地方想新增一些属性,可以用--filter来进行设置 比如:--filter '($event->{Row_ratio} = $event->{Rows_sent}/($event->{Rows_examined}))' ,会新增Row ratio属性*/
-- 概况统计
# Profile
-- 排名,查询指纹,总响应时间及百分比,执行次数,执行平均响应时间,响应时间Variance-to-mean的比率,查询对象
# Rank Query ID Response time Calls R/Call V/M Item
# ==== ================== ============== ===== ======== ===== ============
# 1 0x62C7F17FEBCDF619 733.6364 79.9% 1 733.6364 0.00 CALL insert_emp
# 2 0x1F571989BCCA84ED 91.1762 9.9% 14 6.5126 10.14 SELECT emp
# 3 0x7AD1AD546607A77C 57.0595 6.2% 1 57.0595 0.00 SELECT emp
# MISC 0xMISC 36.4823 4.0% 24 1.5201 0.0 <11 ITEMS> #剩余查询的显示
-- 查询的顺序号(和第一部分的Rank对应),QPS,并发,查询指纹,
# Query 1: 0.08 QPS, 0.16x concurrency, ID 0x5C3D88030F0258F752A830BD792DF4BA at byte 739
# This item is included in the report because it matches --limit.
-- 响应比率
# Scores: V/M = 0.00
-- 分析查询的时间范围
# Time range: 2020-03-01T15:53:12 to 2020-03-01T15:54:16
-- 属性,百分比,总数,最小,最大,95%,标准,中等
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
-- 次数
# Count 55 5
-- 执行时间
# Exec time 38 10s 2s 2s 2s 2s 0 2s
-- 锁时间
# Lock time 38 7ms 209us 6ms 1ms 6ms 2ms 273us
-- 发送到客户端的行数
# Rows sent 43 20 4 4 4 4 0 4
-- 扫描行数
# Rows examine 43 20 4 4 4 4 0 4
-- 查询的字节数
# Query size 63 325 65 65 65 65 0 65
-- 发送和扫描行数比值,用第一部分提到的--filter来进行设置
# Row ratio 55 5 1 1 1 1 0 1
# String:
-- 数据库
# Databases test
-- 主机
# Hosts test2
-- 查询用户
# Users root
-- 查询执行时间分布的直方图:1微妙、10微妙、100微妙、10毫秒、100毫秒,1秒,10秒以上查询的分布情况
# Query_time distribution
# 1us
# 10us
# 100us
# 1ms
# 10ms
# 100ms
# 1s ################################################################
# 10s+
-- 表信息
# Tables
# SHOW TABLE STATUS FROM `test` LIKE 'host'\G
# SHOW CREATE TABLE `test`.`host`\G
-- 执行计划信息
# EXPLAIN /*!50100 PARTITIONS*/
-- 查询SQL
select id,hostname,agent_version,sleep(0.5) from host where id <5\G #如果是非select查询:insert,delete,update,则会转换成select进行explain
①:分析所有的慢查询:
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog
②:分析指定数据库的慢查询:
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --filter '($event->{db} || "") =~ m/^dbsql/i'
③:分析指定用户的慢查询:
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --filter '($event->{user} || "") =~ m/^pmm/i'
④:分析指定IP的慢查询:
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --filter '($event->{host} || $event->{ip} || "") =~ m/^192.168.16.*/i'
⑤:分析指定时间范围的慢查询:
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --since='2023-03-26 00:00:00' --until='2023-03-27 23:59:59'
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --since='1583048987' --until='1583049175'
⑥:分析最近时间的慢查询(最近10h,单位可以为s、和m):
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --since='10h'
⑦:分析指定查询类型的慢查询:
pt-query-digest /data/mysql/my3306/logs/slow.log --type=slowlog --filter '$event->{arg} =~ m/^update/i'
⑧:指定时间、排除指定IP、指定慢查类型(select)写入到表中:
pt-query-digest --user=root --password=root --port=3306 --review h=192.168.16.111,D=slow_query_log,t=global_query_review --history h=192.168.16.111,D=slow_query_log,t=global_query_review_history --limit=0% --filter='($event->{Bytes} = length($event->{arg}) and $event->{hostname}="dbsql") and ($event->{host} || $event->{ip}) !~ m/^localhost$|^192.168.16.1$/i and $event->{arg} =~ m/^select/i' --since='2023-03-23 12:00:00' --until='2023-03-30 13:00:00' /data/mysql/my3306/logs/slow.log --no-report
general log:–type=genlog
$VAR1 = {
Query_time => 0,
Thread_id => '138',
arg => 'SHOW FULL PROCESSLIST',
bytes => 21,
cmd => 'Query',
db => 'mysql',
fingerprint => 'show full processlist',
pos_in_log => 191402,
ts => '2023-03-28T12:21:53.692656Z'
};
general log order-by默认从Query_time:sum改成了Query_time:cnt。general log没有执行时间。
第一部分:总体概况说明,同上面的slow log。
第二部分:查询SQL概况说明。
# Query 1: 0 QPS, 0x concurrency, ID 0x0BBD8F114BF69E6F45609ADE347419D3 at byte 1075144
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.00
# Time range: 2023-03-28T09:38:40.431645Z to 2020-02-29T17:03:19.210317Z
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
-- 次数
# Count 96 16463
-- 执行时间
# Exec time 0 0 0 0 0 0 0 0
-- 查询字节数
# Query size 90 337.62k 21 21 21 21 0 21
# String:
# Databases mysql
# Query_time distribution
# 1us
# 10us
# 100us
# 1ms
# 10ms
# 100ms
# 1s
# 10s+
SHOW FULL PROCESSLIST\G
①:分析所有general log:
pt-query-digest /data/mysql/my3306/data/sdns.log --type=genlog
②:分析指定数据库的general log:
pt-query-digest /data/mysql/my3306/data/sdns.log --type=genlog --filter '($event->{db} || "") =~ m/^dbsql/i'
③:分析指定用户的general log:
pt-query-digest /data/mysql/my3306/data/sdns.log --type=genlog --filter '($event->{user} || "") =~ m/^pmm/i'
④:分析指定IP的general log:只能查询有连接信息的一行
pt-query-digest /data/mysql/my3306/data/sdns.log --type=genlog --filter '($event->{host} || $event->{ip} || "") =~ m/^192.168.16.111/i'
⑤:分析指定查询类型的general log:
pt-query-digest /data/mysql/my3306/data/sdns.log --type=genlog --filter '$event->{arg} =~ m/^update/i'
binlog:–type=binlog
预备:在分析binlog之前,需要先把binlog转换成文本:
mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS mysql-bin.000022 > mysql-bin.000022.txt
$VAR1 = {
Query_time => '0',
Thread_id => '176',
arg => '...',
bytes => 40,
cmd => 'Query',
db => 'xyz',
end_log_pos => '695',
error_code => '0',
fingerprint => '...',
offset => '583',
pos_in_log => 1942,
server_id => '1',
timestamp => '1583133657',
ts => '202303 15:20:57'
};
① 分析所有binlog:
pt-query-digest mysql-bin.000022.txt --type=binlog
②:分析指定数据库的bin log:
pt-query-digest mysql-bin.000022.txt --type=binlog --filter '($event->{db} || "") =~ m/^dbsql/i'
③:分析指定时间范围的binlog
pt-query-digest mysql-bin.000022.txt --type=binlog --since='2023-03-26 15:49:47' --until='2023-03-27 23:59:55'
④:分析最近时间的binlog
pt-query-digest mysql-bin.000022.txt --type=binlog --since='60m'
⑤:分析指定类型的binlog
pt-query-digest mysql-bin.000022.txt --type=binlog --filter '$event->{arg} =~ m/^update/i'
①:抓取show processlist的慢查,转存到指定文件:
间隔1s执行show full processlist 拉取processlist中订阅到的慢查询转存到指定的文件。
pt-query-digest --processlist h=192.168.16.111,u=root,p=123456 --interval=1 --output=slowlog > /tmp/process.log
说明:比较适用于一些云数据库没有看慢查文件的权限。
②:分析show processlist的慢查:配合–run-time使用,可以限制执行时间,到时间(–iterations=1)之后退出并且打印分析。
间隔1s执行show full processlist,永远运行,每30秒生成一次报告
pt-query-digest --processlist h=192.168.16.111,u=root,p=123456 --interval=1 --run-time-mode=clock --run-time=30s --iterations=0
说明:比较适用于一些问题排查方面的工作。
pt-query-digest --review u=root,p=123456,h=192.168.16.111,P=3306,D=xyz,t=query_review --create-review-table test2-slow.log
说明:把慢查询记录到数据库xyz的query_review表中:
表列说明:
字段 | 说明 |
---|---|
checksum | 查询指纹的64位校验和 |
fingerprint | 查询的抽象版本;它的主键 |
sample | 查询样本的文本 |
first_seen | 此类查询的最早时间戳 |
last_seen | 此类查询的最近时间戳 |
reviewed_by | 如果设置,此后将跳过查询 |
reviewed_on | 没有赋予任何特殊含义 |
comments | 没有赋予任何特殊含义 |
注意:如果表中的记录reviewed_by被设了值,则下次运行pt-query-digest --review不会显示该query。
pt-query-digest --history u=root,p=123456,h=192.168.16.111,P=3306,D=xyz,t=query_review_history --create-review-table /data/mysql/my3306/data/sdns.log
说明:把慢查询记录的分析指标转存到数据库xyz的query_review_history表中:
注意:通过report打印出来的信息转存到表中。针对1,2生成的表可以进行关联,来找出那些没有被审计的SQL。通过这2个参数,可以做成一个MySQL的慢查询审计平台。