binlog记录SQL执行时间吗,准不准,时间是否包含锁等待时间

讨论:binlog记录SQL执行时间吗,准不准,时间是否包含锁等待时间

MySQL版本号:

Server version: 5.7.29-log MySQL Community Server (GPL)

 

测试环境如下:

mysql> drop table t1;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t1(id int primary key auto_increment,name varchar(200));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t1 select null,repeat('a',2000);
Query OK, 1 row affected, 1 warning (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 1

mysql> insert into t1 select null,repeat('a',2000) from t1;
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 1
....
插入100W+条数据,让这个表大一些

 

 

找一个DEMO,简单分析下binlog文件,binlog文件本质上是由一个个event组成的,

[root@host101 data]# 
[root@host101 data]# mysqlbinlog -vv --base64-output=decode-rows mysql-bin.000059
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#201107 16:47:03 server id 1  end_log_pos 123 CRC32 0x17ba10af     Start: binlog v 4, server v 5.7.29-log created 201107 16:47:03   ---binlog文件中的第一个event,FORMAT_DESCRIPTION_EVENT,生成时机是binlog文件切换时
# Warning: this binlog is either in use or was not closed properly.
# at 123
#201107 16:47:03 server id 1  end_log_pos 234 CRC32 0x26a0a898     Previous-GTIDs
# 9fef2262-97b1-11ea-92b5-000c29cd3ff3:1-1583,
# adc4403d-97b2-11ea-b803-000c298076e0:1-104                                               ----binlog文件中第二个event,PREVIOUS_GTIDS_LOG_EVENT,用于描述前面所有binary log中包含的GTID SET
# at 234
#201107 16:47:05 server id 1  end_log_pos 299 CRC32 0x79365d3f     GTID    last_committed=0    sequence_number=1    rbr_only=yes   
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '9fef2262-97b1-11ea-92b5-000c29cd3ff3:1584'/*!*/;                 ----binlog文件中第三个event,GTID_LOG_EVENT,用于描述GTID的详细信息,是否为行行为,逻辑时钟详细信息,即last_committed和sequence_number        
# at 299
#201107 16:47:05 server id 1  end_log_pos 377 CRC32 0x44b83854     Query    thread_id=315    exec_time=0    error_code=0   ****---QUERY_EVENT,讨论重点是exec_time,是否是准确时间。****
SET TIMESTAMP=1604738825/*!*/;
SET @@session.pseudo_thread_id=315/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=2/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 377
#201107 16:47:05 server id 1  end_log_pos 423 CRC32 0x9bf22279     Table_map: `ceshi`.`t1` mapped to number 108     ----MAP_EVENT,行模式特有的,用做table_id和实际访问表的映射等。
# at 423
#201107 16:47:05 server id 1  end_log_pos 463 CRC32 0xc3e374f6     Write_rows: table id 108 flags: STMT_END_F       ---WRITE_ROWS_EVENT,是insert语句生成的event.用于记录insert语句的ager_image实际数据。
### INSERT INTO `ceshi`.`t1`
### SET
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
# at 463
#201107 16:47:05 server id 1  end_log_pos 494 CRC32 0x86bb8b11     Xid = 14938
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

 

****---QUERY_EVENT,讨论重点是exec_time,是否是准确时间。****
exec_time是在QUERY_EVENT中记录的,
根据之前学习【深入理解MySQL主从32讲】,结论是:
DML:执行时间记录的是第一条数据更改后的时间,而不是真正本条DML语句执行的时间(一个DML语句可能修改很多条记录),往往这个时间非常短短,不能正确的表示DML语句执行的时间。语句部分记录的是BEGIN。
DDL:执行时间是实际语句的执行时间,部分语句记录的是实际的语句。

1、验证下DML时间统计的结论,命令执行时间10.30秒,
binlog中解析到的exec_time=0 ,之前的结成立,exec_time记录是修改第一条记录的时间,修改一条记录的时间是很快的。
mysql> flush binary logs;
Query OK, 0 rows affected (0.02 sec)

mysql> update t1 set name=repeat('c',2000);
Query OK, 131072 rows affected, 65535 warnings (10.30 sec)
Rows matched: 131072  Changed: 131072  Warnings: 131072

binlog

#201107 17:21:09 server id 1  end_log_pos 377 CRC32 0x6f3d46e9  Query   thread_id=315   exec_time=0     error_code=0
SET TIMESTAMP=1604740869/*!*/;
SET @@session.pseudo_thread_id=315/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=2/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 377
#201107 17:21:09 server id 1  end_log_pos 426 CRC32 0x139eedd0  Table_map: `ceshi`.`t1` mapped to number 119
# at 426
#201107 17:21:09 server id 1  end_log_pos 8328 CRC32 0x07294435         Update_rows: table id 119
# at 8328
#201107 17:21:09 server id 1  end_log_pos 16230 CRC32 0x3fca917d        Update_rows: table id 119
# at 16230
#201107 17:21:09 server id 1  end_log_pos 24132 CRC32 0xd40fb927        Update_rows: table id 119
# at 24132
...........

 

2、验证下DDL命令时间统计,命令执行时间1.57秒,

binlog中exec_time=2 ,应该是把时间四舍五入了,结论成立。

mysql> flush binary logs;
Query OK, 0 rows affected (0.01 sec)

mysql> alter table t1 add age int;
Query OK, 0 rows affected (1.57 sec)
Records: 0  Duplicates: 0  Warnings: 0

binlog

#201107 17:24:22 server id 1  end_log_pos 406 CRC32 0x26d06826  Query   thread_id=315   exec_time=2     error_code=0
use `ceshi`/*!*/;
SET TIMESTAMP=1604741062/*!*/;
SET @@session.pseudo_thread_id=315/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=2/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
alter table t1 add age int
/*!*/;

 

3、之前的实验都是在没有锁发生的情况测试的,如果遇到Innodb行锁,或MDL锁,不知exec_time是否会包含这个时间,测试如下,先删掉之前添回执age列,重新做测试 。

  3.1故意让update命令产生行锁等待,看下binlog的exec_time时间。

t1时间

session1:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where id=1 for update;
+----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name                                                                                                                                                                                                     |
+----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|  1 | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

t2时间

sessino2:

mysql> use ceshi;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> update t1 set name=repeat('d',2000);      ----处于锁等待状态

过一会儿(大约10秒钟左右,心中默数的),

t3时间,session1释放掉锁

mysql> select * from t1 where id=1 for update;
+----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name                                                                                                                                                                                                     |
+----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|  1 | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
+----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

t4时间,session2持有锁开始更新记录,SQL显示执行了22.11秒(其中包括锁等待时间)

mysql> update t1 set name=repeat('d',2000);
Query OK, 131072 rows affected, 65535 warnings (22.11 sec)
Rows matched: 131072  Changed: 131072  Warnings: 131072

binlog

#201107 21:37:03 server id 1  end_log_pos 377 CRC32 0x01b20225  Query   thread_id=607   exec_time=13    error_code=0
SET TIMESTAMP=1604756223/*!*/;
SET @@session.pseudo_thread_id=607/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=2/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 377
#201107 21:37:03 server id 1  end_log_pos 426 CRC32 0x87b8f0c1  Table_map: `ceshi`.`t1` mapped to number 121
# at 426
#201107 21:37:03 server id 1  end_log_pos 8328 CRC32 0xd5053a6d         Update_rows: table id 121
# at 8328
#201107 21:37:03 server id 1  end_log_pos 16230 CRC32 0xede6ef25        Update_rows: table id 121
# at 16230
........

  3.1小结:binlog中exec_time记录行锁等待的时间,实际锁等待时间应该就是13秒,但仍然不能代表update 语句实际执行时间, 因为它实际计算的是update语句更新第一条记录需要的时间。

 

 

  3.2故意让update命令产生MDL锁等待,看下binlog的exec_time时间。

t1时间

session1:锁定t1表

mysql> flush table t1 with read lock;
Query OK, 0 rows affected (0.01 sec)

t2时间

session2:做更新,处于卡住状态。

mysql> update t1 set name=repeat('e',2000);

执行个show processlist,确定现在是等待获取MDL锁状态 

mysql> show processlist;
+-----+---------+-----------------------+--------------------+------------------+-------+---------------------------------------------------------------+-------------------------------------+
| Id  | User    | Host                  | db                 | Command          | Time  | State                                                         | Info                                |
+-----+---------+-----------------------+--------------------+------------------+-------+---------------------------------------------------------------+-------------------------------------+
|  12 | root    | 192.168.150.150:36454 | information_schema | Sleep            |    26 |                                                               | NULL                                |
| 322 | root    | 192.168.150.102:56206 | NULL               | Binlog Dump GTID | 17926 | Master has sent all binlog to slave; waiting for more updates | NULL                                |
| 323 | root    | 192.168.150.103:43044 | NULL               | Binlog Dump GTID | 17910 | Master has sent all binlog to slave; waiting for more updates | NULL                                |
| 607 | root    | localhost             | ceshi              | Query            |     6 | Waiting for table metadata lock                               | update t1 set name=repeat('e',2000) |
| 609 | root    | localhost             | ceshi              | Sleep            |    11 |                                                               | NULL                                |
| 620 | monitor | 192.168.150.150:40076 | NULL               | Sleep            |     0 |                                                               | NULL                                |
| 621 | monitor | 192.168.150.150:40078 | NULL               | Sleep            |     5 |                                                               | NULL                                |
| 631 | root    | localhost             | NULL               | Query            |     0 | starting                                                      | show processlist                    |
+-----+---------+-----------------------+--------------------+------------------+-------+---------------------------------------------------------------+-------------------------------------+
8 rows in set (0.00 sec)

t3时间

session1:释放MDL锁

mysql> flush table t1 with read lock;
Query OK, 0 rows affected (0.01 sec)

mysql> unlock tables;
Query OK, 0 rows affected (0.01 sec)

t4时间:

session2:执行完成了

mysql> update t1 set name=repeat('e',2000);
Query OK, 131072 rows affected, 65535 warnings (2 min 46.26 sec)
Rows matched: 131072  Changed: 131072  Warnings: 131072

mysql> 

binlog

#201107 21:46:44 server id 1  end_log_pos 54512694 CRC32 0xe9c2432b     GTID    last_committed=1        sequence_number=2       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '9fef2262-97b1-11ea-92b5-000c29cd3ff3:1615'/*!*/;
# at 54512694
#201107 21:46:44 server id 1  end_log_pos 54512772 CRC32 0x47413c2e     Query   thread_id=607   exec_time=157   error_code=0
SET TIMESTAMP=1604756804/*!*/;
BEGIN
/*!*/;
# at 54512772
#201107 21:46:44 server id 1  end_log_pos 54512821 CRC32 0x7384f6e6     Table_map: `ceshi`.`t1` mapped to number 122
# at 54512821
#201107 21:46:44 server id 1  end_log_pos 54520723 CRC32 0x8570824e     Update_rows: table id 122
# at 54520723
#201107 21:46:44 server id 1  end_log_pos 54528625 CRC32 0xeb6a3741     Update_rows: table id 122

  3.2小结:binlog中exec_time记录MDL锁等待的时间,实际锁等待时间应该就是157秒,但仍然不能代表update 语句实际执行时间, 因为它实际计算的是update语句更新第一条记录需要的时间。

  通过个结论,我们可以后期通过exec_time内容分析当时的DML操作有没有遇到行锁或MDL锁。

 

4.1

DDL命令不会遇到行锁,但会遇到MDL锁,测试DDL命令在遇到MDL锁的时候,binlog中exec_time是否有记录。

t1时间

session1:

mysql> flush table t1 with read lock;
Query OK, 0 rows affected (0.00 sec)

t2时间

session2:

mysql> alter table t1 add age int;

执行个show processlist,确定现在是等待获取MDL锁状态 

mysql> show processlist;
+-----+---------+-----------------------+--------------------+------------------+-------+---------------------------------------------------------------+----------------------------+
| Id  | User    | Host                  | db                 | Command          | Time  | State                                                         | Info                       |
+-----+---------+-----------------------+--------------------+------------------+-------+---------------------------------------------------------------+----------------------------+
|  12 | root    | 192.168.150.150:36454 | information_schema | Sleep            |    53 |                                                               | NULL                       |
| 322 | root    | 192.168.150.102:56206 | NULL               | Binlog Dump GTID | 18914 | Master has sent all binlog to slave; waiting for more updates | NULL                       |
| 323 | root    | 192.168.150.103:43044 | NULL               | Binlog Dump GTID | 18898 | Master has sent all binlog to slave; waiting for more updates | NULL                       |
| 607 | root    | localhost             | ceshi              | Query            |    83 | Waiting for table metadata lock                               | alter table t1 add age int |
| 609 | root    | localhost             | ceshi              | Sleep            |    94 |                                                               | NULL                       |
| 637 | monitor | 192.168.150.150:40180 | NULL               | Sleep            |     1 |                                                               | NULL                       |
| 643 | root    | localhost             | NULL               | Query            |     0 | starting                                                      | show processlist           |
+-----+---------+-----------------------+--------------------+------------------+-------+---------------------------------------------------------------+----------------------------+
7 rows in set (0.00 sec)

t3时间

session1:释放掉持有的MDL锁

mysql> flush table t1 with read lock;
Query OK, 0 rows affected (0.00 sec)

mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)

t4时间

session2:执行了124.83秒

mysql> alter table t1 add age int;
Query OK, 0 rows affected (2 min 4.83 sec)
Records: 0  Duplicates: 0  Warnings: 0

binlog

#201107 22:01:55 server id 1  end_log_pos 406 CRC32 0xa73826c4  Query   thread_id=607   exec_time=125   error_code=0
use `ceshi`/*!*/;
SET TIMESTAMP=1604757715/*!*/;
SET @@session.pseudo_thread_id=607/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=2/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
alter table t1 add age int
/*!*/;

 

   3.2总结:binlog中exec_time会计算DDL命令等待MDL锁的时间。

 

总结:

1、DDL命令和DML命令,在记binlog时exec_time都会算上锁等待的时间(包括行锁和MDL锁)。

2、DML操作的exec_time可以倒推出当时执行命令的时候有没有遇到行锁或MDL锁。

3、由于DDL操作记录的是命令执行所有时间,无法倒推出执行时有没有遇到MDL锁,只能根据经验看,这个命令执行耗时是否不正常,如果不正常,可以怀疑执行时遇到了MDL锁。

posted on 2020-11-07 22:09  柴米油盐酱醋  阅读(1966)  评论(0编辑  收藏  举报

导航