Preface
 
    There always be some table join operations in our SQL statement.Although we can know details of table join information from explain opertion by json format.Whatif you are not using MySQL 5.7?Is there a tool which can tell us how the tables are used in join operations?
    
Introduce
 
    pt-table-usage is simply used to anaylyze how the queries use tables.It can indicate the data flow by the contexts in which table appear.We can either get these information from query statement directly(using "--query" option) or from a log file(It should be slow log format) insetead.
 
Procedure
 
Usage
 pt-table-usage [OPTIONS] [FILES]
Common parameter
 --constant-data-value //Specify the table to print as the source for constant data(default "DUAL").
--continue-on-error //It won't stop when getting errors(default "yes").
--create-table-definitions //Specify a file to read definitions in it.
--explain-extended //Specify a server to avoid ambiguous names of columns and tables.
--id-attribute //Specify a format to identify each event(default query ID).
--progress //Specify the way to print progress(default time,30s).
--query //Speicy reading from a qeury instead of log file.
Example
 
Print table usage relevant with constant query(insert,update).
 //Create a test table.
(zlm@192.168.1.101 )[zlm]>create table test_table_usage(
-> id int,
-> name char()
-> ) engine=innodb;
Query OK, rows affected (0.02 sec) [root@zlm2 :: ~]
#pt-table-usage --query='insert into zlm.test_table_usage values(1,'zlm');'
Query_id: 0x4467805469FEF40B. //The
INSERT zlm.test_table_usage
SELECT DUAL //When specifying the constant value,it will print "DUAL" after "SELECT". [root@zlm2 :: ~]
#pt-table-usage --query='update zlm.test_table_usage set id=2 where name='zlm';'
Query_id: 0xB2EE79AD4DA99C2B.
UPDATE zlm.test_table_usage
SELECT DUAL //When specifying the constant value,it will print "DUAL" after "SELECT".
WHERE zlm.test_table_usage //There's a condition in query statment.It will be printed here. (zlm@192.168.1.101 )[zlm]>select * from test_table_usage;
Empty set (0.00 sec) //There're no records changed at all in the test table.Because those two queries are just query operations which won't be really executed.
Print table usage relevant with query(select).
 [root@zlm2 :: ~]
#pt-table-usage --query='select t1.id,t1.pad from sbtest1 as t1 join sbtest2 as t2 where t1.pad=t2.pad;'
Query_id: 0x016CE309DD3D9FA3.
SELECT sbtest1 //This time,it shows the specific table name which your query data in.
TLIST sbtest1 //"TLIST" means full table scan will be used in the above query.
TLIST sbtest2
WHERE sbtest1 [root@zlm2 :: ~]
#pt-table-usage --query='select t1.id,t2.pad from sbtest1 as t1 join sbtest2 as t2 where t1.pad=t2.pad;'
Query_id: 0x016CE309DD3D9FA3.
SELECT sbtest1
SELECT sbtest2 //Have you seen the difference?The column "pad" belongs to the table "sbtest2" in the query,So there comes the line.
TLIST sbtest1 //"TLIST" means full table scan will be used in the above query either.
TLIST sbtest2
WHERE sbtest1
Print table usage according to the slow log file.
 
 (zlm@192.168.1.101 )[sysbench]>show variables like '%slow%';
+---------------------------+----------+
| Variable_name | Value |
+---------------------------+----------+
| log_slow_admin_statements | OFF |
| log_slow_slave_statements | ON |
| slow_launch_time | |
| slow_query_log | ON | //Make sure the slow log is functional.
| slow_query_log_file | slow.log |
+---------------------------+----------+
rows in set (0.00 sec) (zlm@192.168.1.101 )[sysbench]>show variables like 'long_query%';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 1.000000 | //Check out the threashold of slow log.
+-----------------+----------+
row in set (0.00 sec) (zlm@192.168.1.101 )[sysbench]>set long_query_time=;
Query OK, rows affected (0.00 sec) (zlm@192.168.1.101 )[sysbench]>show variables like 'long_query%';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 0.000000 | //Let the slow log record every SQL statement.
+-----------------+----------+
row in set (0.00 sec) (zlm@192.168.1.101 )[sysbench]>show tables;
+--------------------+
| Tables_in_sysbench |
+--------------------+
| sbtest1 |
| sbtest2 |
+--------------------+
rows in set (0.00 sec) (zlm@192.168.1.101 )[sysbench]>select count(*) from sbtest1; //Query 1.
+----------+
| count(*) |
+----------+
| |
+----------+
row in set (0.00 sec) (zlm@192.168.1.101 )[sysbench]>select count(*) from sbtest2; //Query 2.
+----------+
| count(*) |
+----------+
| |
+----------+
row in set (0.00 sec) (zlm@192.168.1.101 )[sysbench]>select t1.id,t2.pad from sbtest1 as t1 join sbtest2 as t2 where t1.k<t2.k; //Query 3.
Killed //The mysql client is killed,because the query time is too long. [root@zlm2 :: ~]
#ps aux|grep mysql
mysql 1.5 3.0 pts/ Sl : : mysqld --defaults-file=/data/mysql/mysql3306/my.cnf
root 0.0 0.0 pts/ S+ : : grep --color=auto mysql [root@zlm2 :: ~] //Slow log shows the details.
[root@zlm2 :: /data/mysql/mysql3306/data]
#tail -f slow.log # Time: --26T03::30.313395+:
# User@Host: zlm[zlm] @ zlm2 [192.168.1.101] Id:
# Query_time: 0.000170 Lock_time: 0.000070 Rows_sent: Rows_examined:
SET timestamp=;
show tables;
# Time: --26T03::43.141016+:
# User@Host: zlm[zlm] @ zlm2 [192.168.1.101] Id:
# Query_time: 0.002259 Lock_time: 0.000061 Rows_sent: Rows_examined:
SET timestamp=;
select count(*) from sbtest1; //Query 1.
# Time: --26T03::57.593601+:
# User@Host: zlm[zlm] @ zlm2 [192.168.1.101] Id:
# Query_time: 0.001549 Lock_time: 0.000060 Rows_sent: Rows_examined:
SET timestamp=;
select count(*) from sbtest2; //Query 2.
# Time: --26T03::39.471206+:
# User@Host: zlm[zlm] @ zlm2 [192.168.1.101] Id:
# Query_time: 33.401928 Lock_time: 0.000084 Rows_sent: Rows_examined: //Too many rows are examinted.It's a cartesian join.
SET timestamp=;
select t1.id,t2.pad from sbtest1 as t1 join sbtest2 as t2 where t1.k<t2.k; //Query 3. //Let's see what will show in pt-table-usage.
[root@zlm2 :: ~]
#pt-table-usage /data/mysql/mysql3306/data/slow.log
Query_id: 0x999ECD050D719733. //Query 1.
SELECT sbtest1 Query_id: 0x999ECD050D719733. //Query 2.
SELECT sbtest2 Query_id: 0x923C5317557357E2. //Query 3.
SELECT sbtest1
SELECT sbtest2
JOIN sbtest1
JOIN sbtest2 //No "WHERE" condition instructions after this line(Is that because of the killing operation?I'm not sure about it). //Let's check out the execution plan.
(zlm@192.168.1.101 )[sysbench]>explain select t1.id,t2.pad from sbtest1 as t1 join sbtest2 as t2 where t1.k<t2.k;
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+------------------------------------------------+
| | SIMPLE | t1 | NULL | index | k_1 | k_1 | | NULL | | 100.00 | Using index |
| | SIMPLE | t2 | NULL | ALL | k_2 | NULL | NULL | NULL | | 33.33 | Range checked for each record (index map: 0x2) |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+------------------------------------------------+
rows in set, warning (0.00 sec) (zlm@192.168.1.101 )[sysbench]>explain format=json select t1.id,t2.pad from sbtest1 as t1 join sbtest2 as t2 where t1.k<t2.k\G
*************************** . row ***************************
EXPLAIN: {
"query_block": {
"select_id": ,
"cost_info": {
"query_cost": "19747226.04" //It's really an amazingly tremendous cost of the query.No wonder why it was killed.
},
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "index",
"possible_keys": [
"k_1"
],
"key": "k_1",
"used_key_parts": [
"k"
],
"key_length": "",
"rows_examined_per_scan": ,
"rows_produced_per_join": ,
"filtered": "100.00",
"using_index": true,
"cost_info": {
"read_cost": "161.00",
"eval_cost": "1987.20",
"prefix_cost": "2148.20",
"data_read_per_join": "5M"
},
"used_columns": [
"id",
"k"
]
}
},
{
"table": {
"table_name": "t2",
"access_type": "ALL",
"possible_keys": [
"k_2"
],
"rows_examined_per_scan": ,
"rows_produced_per_join": ,
"filtered": "33.33",
"range_checked_for_each_record": "index map: 0x2",
"cost_info": {
"read_cost": "258.64",
"eval_cost": "6580948.13",
"prefix_cost": "19747226.04",
"data_read_per_join": "16G" //What a big size!
},
"used_columns": [
"k",
"pad"
]
}
}
]
}
}
row in set, warning (0.00 sec)
Summary

  • It's very simple to use pt-table-usage,there're only several options of it.
  • pt-table-usage can be used in either a query statement by specifying "--query" or a log file such as slow log by specifying the path of it.
  • If your MySQL version is below 5.7,you can consider using pt-table-usage to analyze the join information of tables in queries.

 

Percona-Tookit工具包之pt-table-usage的更多相关文章

  1. haproxy实现会话保持(2):stick table

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  2. Linux后台开发工具箱

    https://files-cdn.cnblogs.com/files/aquester/Linux后台开发工具箱.pdf 目录 目录 1 1. 前言 3 2. 脚本类工具 3 2.1. sed命令- ...

  3. Mysql: pt-table-checksum 和 pt-table-sync 检查主从一致性,实验过程

    一.安装 percona 包 1.安装仓库的包 https://www.percona.com/doc/percona-repo-config/yum-repo.html sudo yum insta ...

  4. Linux后台开发工具箱-葵花宝典

    Linux后台开发工具箱-葵花宝典 一见 2016/11/4 目录 目录 1 1. 前言 4 2. 脚本类工具 4 2.1. 双引号和单引号 4 2.2. 取脚本完整文件路径 5 2.3. 环境变量和 ...

  5. [知识库分享系列] 二、.NET(ASP.NET)

    最近时间又有了新的想法,当我用新的眼光在整理一些很老的知识库时,发现很多东西都已经过时,或者是很基础很零碎的知识点.如果分享出去大家不看倒好,更担心的是会误人子弟,但为了保证此系列的完整,还是选择分享 ...

  6. Percona-Toolkit 之 pt-table-sync 总结

    pt-table-sync - Synchronize MySQL table data efficiently. pt-table-sync synchronizes data efficientl ...

  7. PatentTips - Supporting address translation in a virtual machine environment

    BACKGROUND A conventional virtual-machine monitor (VMM) typically runs on a computer and presents to ...

  8. 推荐几款MySQL相关工具

    前言: 随着互联网技术的不断发展, MySQL 相关生态也越来越完善,越来越多的工具涌现出来.一些公司或个人纷纷开源出一些不错的工具,本篇文章主要介绍几款 MySQL 相关实用工具.提醒下,这里并不介 ...

  9. Markdown编辑器语法指南2

    人的一切痛苦, 本质上都是对自己的无能的愤怒. --王小波 1 Markdown编辑器的基本用法 1.1 代码 如果你只想高亮语句中的某个函数名或关键字,可以使用 `function_name()` ...

随机推荐

  1. dd-wrt ddns更新失败由于电信提供的ip不是公网ip

    由于电信提供的ip地址原来是公网的ip,后来电信通过nat提供一个内网ip,导致ddns更新失败.电话给电信客服10000号,让他们修改回来之后就可以了. 如果ddns更新失败,尤其是原本是正常的,后 ...

  2. php通过gbk编码判断 含有连续数字 可用于判断QQ号,手机号等。

    有可能有些输入,不希望让用户的评论或者私信中含有类似于QQ号,手机号的文本,比如交友网站.还有些恶意SEO通过,构造恶意检索词,检索词中包含QQ,手机号等,让百度爬取到,增加展现.也需要将这些检索词屏 ...

  3. [Pytorch] pytorch笔记 <三>

    pytorch笔记 optimizer.zero_grad() 将梯度变为0,用于每个batch最开始,因为梯度在不同batch之间不是累加的,所以必须在每个batch开始的时候初始化累计梯度,重置为 ...

  4. P1151 子数整数

    题目描述 对于一个五位数a_1a_2a_3a_4a_5a1​a2​a3​a4​a5​,可将其拆分为三个子数: sub_1=a_1a_2a_3sub1​=a1​a2​a3​ sub_2=a_2a_3a_ ...

  5. ios各层

    数据持久层.业务逻辑层.表示层 数据持久层: 持久化(Persistence)意思就是当你退出app的时候它还会存在. dao层:DAO (Data Access Object) 数据访问对象是一个面 ...

  6. Spring boot 集成三种定时任务方式

    三种定时任务方式分别为 org.springframework.scheduling.annotation.Scheduled java.util.concurrent.ScheduledExecut ...

  7. linux flushing file system caches

    We may drop the file system caches on Linux to free up memory for applications. Kernels 2.6.16 and n ...

  8. C#声明方法

    一.声明方法 方法是类中用于执行计算或其它行为的成员. 方法可以分为: ?静态方法:可以通过类进行访问.?实例方法:可以通过类的对象进行访问. 1. C#方法的声明 声明方法的语法格式如下: 访问修饰 ...

  9. Shell简介:1分钟理解什么是Shell 脚本语言 解释器 以及编译器和编译语言

    Shell简介:1分钟理解什么是Shell 脚本语言 解释器 以及编译器和编译语言 现在我们使用的操作系统(Windows.Mac OS.Android.iOS 等)都是带图形界面的,简单直观,容易上 ...

  10. java基础IO流 复制键盘录入的目录,复制其中的.java文件到指定目录,指定目录中有重名,则改名 对加密文件计算字母个数

    package com.swift.jinji; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; im ...