Skip to content

pt-table-usage

分析查询如何使用表——不仅指出读写了哪些表,还指出表之间的数据流向。

语法

bash
pt-table-usage [OPTIONS] [FILES]

从日志读取查询并分析其表使用方式;未指定 FILE 时读标准输入,为每个查询打印一份报告。

用法示例

本工具主要读取慢查询日志(或 --query 给的单条查询)来分析表使用关系,多数场景不需要连接 MySQL;只有用 --explain-extended 消解列/表名歧义时才需提供 DSN。命令里的日志路径、查询串、库名替换成你自己的即可。

场景:分析慢日志的表依赖

拿到一份慢日志,先整体看每条查询都碰了哪些表、数据怎么在表之间流动:

bash
pt-table-usage /var/log/mysql/slow.log

场景:直接分析一条查询

不想先落慢日志,临时验证某条多表 UPDATE/INSERT..SELECT 的数据流向,直接用 --query

bash
pt-table-usage --query "UPDATE t1 JOIN t2 USING(id) SET t1.c=t2.c WHERE t1.id > 10"

场景:多表查询列名歧义时消解

查询里列没加表前缀、工具无法确定列属于哪张表时,给它一台服务器执行 EXPLAIN EXTENDED 来解析(DSN 不写明文密码):

bash
pt-table-usage /var/log/mysql/slow.log --explain-extended h=localhost

场景:用建表定义消解歧义(免连库)

不方便连库时,把 mysqldump --no-data 的库表结构存成文件,让工具据此限定列归属:

bash
pt-table-usage /var/log/mysql/slow.log --create-table-definitions /tmp/schema.sql

场景:日志没打印库名时指定默认库

日志里没记录默认数据库、导致 EXPLAIN EXTENDED 失败,用 --database 补上默认库:

bash
pt-table-usage /var/log/mysql/slow.log --database appdb

场景:只分析某个库的查询

日志里混杂多个库,只想看 appdb 的表依赖,用 --filter 按 db 过滤事件:

bash
pt-table-usage /var/log/mysql/slow.log \
  --filter '($event->{db} || "") eq "appdb"'

功能说明

日志应为 MySQL 慢查询日志格式。

"表使用"不只是查询读写了哪些表,还包括数据流(data in / data out): 工具根据表在查询中出现的上下文判断数据流。一条查询可以同时在多个上下文中使用同一张表, 输出会列出每张表的每个上下文,这份"上下文-表"清单描述了数据如何在表之间流动。

工具把数据流分析到列级别,因此查询中的列最好能无歧义地标识: 单表查询没有困难;多表查询且列名未加表前缀时,需要 EXPLAIN EXTENDED + SHOW WARNINGS 来确定列属于哪张表。若日志中未打印默认数据库,EXPLAIN EXTENDED 可能失败, 此时可用 --database 指定默认数据库,或用 --create-table-definitions 消除歧义。

输出

为每条查询中的每张表打印使用报告,例如:

Query_id: 0x1CD27577D202A339.1
UPDATE t1
SELECT DUAL
JOIN t1
JOIN t2
WHERE t1

第一行是查询 ID(默认与 pt-query-digest 报告中的一致,即查询"指纹"的 MD5 校验值), 格式为 查询ID.表编号。表编号对多表 UPDATE 查询中每张被更新的表递增 1 (其他类型查询恒为 1;不支持多表 DELETE)。

其后的"上下文-表"行含义如下:

  • SELECT:查询从该表取数据——或作为结果集返回(SELECT 查询必有), 或流向其他表(INSERT/UPDATE 的数据来源)。不来自任何表的值以 DUAL 表示 (如字面量 "bar"、42、NOW() 等,可用 --constant-data-value 更改该名称)。
  • 其他动词(INSERT/UPDATE/DELETE 等):表示查询以某种方式修改该表的数据; 若其后跟着 SELECT 上下文,则说明数据从 SELECT 的表流向该表(如 INSERT..SELECT)。 不支持 SET、LOAD 和多表 DELETE。
  • JOIN:被连接的表(显式 JOIN 或 WHERE 中的隐式连接,如 t1.id = t2.id)。
  • WHERE:WHERE 子句中用于过滤的表(不含隐式连接,隐式连接归入 JOIN)。 只列去重后的表。
  • TLIST:查询访问但不属于其他上下文的表,通常是隐式笛卡尔积 (如 SELECT * FROM t1, t2 中无连接条件的 t1、t2)。

退出状态

出错时退出码为 1,无错误为 0。

选项

选项说明
--ask-pass连接 MySQL 时交互式询问密码
--[no]buffer-stdout默认开启 STDOUT 缓冲;使用 tee、kubectl logs 等后处理工具想看到实时进度时可关闭
-A, --charset类型:string。默认字符集(utf8 时设置 binmode/mysql_enable_utf8 并执行 SET NAMES UTF8
--config类型:Array。读取逗号分隔的配置文件列表;如指定必须放在命令行第一个选项的位置
--constant-data-value类型:string;默认:DUAL。常量数据(字面量、函数值等非表来源数据)打印为的"表名"
--[no]continue-on-error默认:yes。出错时继续工作
--create-table-definitions类型:array。从这些文件读取 CREATE TABLE 定义(可保存 mysqldump --no-data 的输出);用于限定表/列名;跨库同名表等歧义无法解决
--daemonizefork 到后台并与 shell 脱离,仅限 POSIX 系统
-D, --database类型:string。默认数据库
-F, --defaults-file类型:string。只从给定文件读取 mysql 选项,必须给绝对路径
--explain-extended类型:DSN。执行 EXPLAIN EXTENDED 的服务器,用于消解未限定的列/表名歧义
--filter类型:string。丢弃该 Perl 代码不返回 true 的事件(与 pt-query-digest 的 filter 相同机制,可为代码串或代码文件)
--help显示帮助并退出
-h, --host类型:string。要连接的主机
--id-attribute类型:string。用该属性标识事件;默认为查询 ID(指纹的 MD5)
--log类型:string。daemonize 时把全部输出打印到该文件
-s, --mysql_ssl类型:int。创建 SSL MySQL 连接
-p, --password类型:string。连接密码(含逗号需转义)
--pid类型:string。创建指定的 PID 文件;冲突规则与自动清理见官方文档
-P, --port类型:int。连接端口
--progress类型:array;默认:time,30。向 STDERR 打印进度:`percentage
--query类型:string。分析该指定查询而不是读日志文件
--read-timeout类型:time;默认:0。等待输入事件的最长时间,0 表示永远等;超时后停止读取并打印报告。需要 Perl POSIX 模块
--run-time类型:time。运行多久后退出;默认永远运行(可用 Ctrl-C 中断)
--set-vars类型:Array。以逗号分隔的 变量=值 列表设置 MySQL 变量;默认 wait_timeout=10000;无法设置时打印警告并继续
-S, --socket类型:string。连接使用的 socket 文件
-u, --user类型:string。登录用户(若非当前用户)
--version显示版本并退出

DSN 选项

DSN 部分说明
Acharset默认字符集
D默认数据库(不复制)
Fmysql_read_default_file只从给定文件读取默认选项(不复制)
hhost要连接的主机
ppassword连接密码(含逗号需转义)
Pport连接端口
Smysql_socket连接使用的 socket 文件(不复制)
uuser登录用户(若非当前用户)
smysql_ssl创建 SSL 连接

其他信息

  • 作者:Daniel Nichter

  • 通用说明:已知问题的反馈方式、PTDEBUG 调试安全提示、系统要求基线,见 通用说明

更多细节请阅读 官方文档

Percona Toolkit 中文文档 · 社区维护的第三方学习站