在上一期《日志记录等混杂表|全方位认识 mysql 系统库》中,我们详细介绍了mysql系统库中的日志记录表,本期我们将为大家带来系列第九篇《应用示例荟萃|全方位认识 mysql 系统库》,也是"全方位认识 mysql 系统库"的最后一篇,下面请跟随我们一起开始 mysql 系统库的系统学习之旅吧
1、查看用户不同作用域的权限
1.1. 查看全局权限
首先创建一个具有全局权限的用户test_global,并授予select权限,全局权限在操作上使用. 表示,如下
root@localhost : (none) 12:51:46> use mysql
Database changed
root@localhost : mysql 12:52:58> grant select on *.* to test_global@'%' identified by 'test';
Query OK, 0 rows affected, 1 warning (0.00 sec)
然后,我们查询全局权限表mysql.user验证一下Select_priv列是否为Y,其他列是否为N
root@localhost : mysql 12:53:35> select * from user where user='test_global'\G
*************************** 1. row ***************************
Host: %
User: test_global
Select_priv: Y # 从这里可以看到,mysql.user表中只有select权限标记列为Y,其余的权限列为N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: mysql_native_password
authentication_string: *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
password_expired: N
password_last_changed: 2018-08-19 12:53:35
password_lifetime: NULL
account_locked: N
1 row in set (0.00 sec)
然后我们在查询一下库级别权限表db,表级别权限表tables_priv表,列级别权限表columns_priv表,理论情况下对于test_global用户不应在这三张表中有权限记录,通过如下查询结果也可以证实确实没有记录
root@localhost : mysql 12:53:58> select * from db where user='test_global'\G
Empty set (0.02 sec)
root@localhost : mysql 12:54:13> select * from tables_priv where user='test_global'\G
Empty set (0.00 sec)
root@localhost : mysql 12:54:22> select * from columns_priv where user='test_global'\G
Empty set (0.00 sec)
1.2. 查看库级别权限
首先创建一个测试数据库,然后创建一个具有库级别权限的用户test_db,并授予select权限,库级别权限在操作上使用db_name.* 表示,如下
root@localhost : mysql 12:55:30> create database test_grant;
Query OK, 1 row affected (0.01 sec)
root@localhost : mysql 12:55:42> grant select on test_grant.* to test_db@'%' identified by 'test';
Query OK, 0 rows affected, 1 warning (0.00 sec)
然后,我们查询全局权限表mysql.user发现test_db用户在该表中有记录,但是所有权限标记列为N。确认test_db用户并不具有全局权限,该表中存在着test_db用户的记录是因为要在这里保存密码加密字符串、密码过期时间、账号锁定状态等信息
root@localhost : mysql 12:56:09> select * from user where user='test_db'\G
*************************** 1. row ***************************
Host: %
User: test_db
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: mysql_native_password
authentication_string: *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
password_expired: N
password_last_changed: 2018-08-19 12:56:09
password_lifetime: NULL
account_locked: N
1 row in set (0.00 sec)
然后我们在查询一下库级别权限表db,表级别权限表tables_priv表,列级别权限表columns_priv表,理论情况下对于test_db用户只会在mysql.db表中存在库级别select权限记录,其余权限表不应该有记录,通过下面的查询结果也证实了只有mysql.db表中存在test_db用户的权限记录
root@localhost : mysql 12:56:29> select * from db where user='test_db'\G
*************************** 1. row ***************************
Host: %
Db: test_grant
User: test_db
Select_priv: Y # 库级别select权限列为Y,其余权限标记列为N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Execute_priv: N
Event_priv: N
Trigger_priv: N
1 row in set (0.00 sec)
root@localhost : mysql 12:56:41> select * from tables_priv where user='test_db'\G
Empty set (0.00 sec)
root@localhost : mysql 12:56:53> select * from columns_priv where user='test_db'\G
Empty set (0.00 sec)
1.3. 查看表级别权限
首先创建一张测试表,然后创建一个具有表级别权限的用户test_table,并授予select权限,库级别权限在操作上使用db_name.table_name 表示,如下
root@localhost : mysql 12:57:00> use test_grant
Database changed
root@localhost : test_grant 12:57:27> create table test_table_grant(id int);
Query OK, 0 rows affected (0.03 sec)
root@localhost : test_grant 12:57:52> grant select on test_grant.test_table_grant to test_table@'%' identified by 'test';
Query OK, 0 rows affected, 1 warning (0.01 sec)
然后,我们查询全局权限表mysql.user发现test_table用户在该表中有记录,但是所有权限标记列为N。确认test_table用户并不具有全局权限,该表中存在着test_table用户的记录是因为要在这里保存密码加密字符串、密码过期时间、账号锁定状态等信息
root@localhost : test_grant 12:59:21> select * from mysql.user where user='test_table'\G
*************************** 1. row ***************************
Host: %
User: test_table
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: mysql_native_password
authentication_string: *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
password_expired: N
password_last_changed: 2018-08-19 12:58:13
password_lifetime: NULL
account_locked: N
1 row in set (0.00 sec)
然后我们在查询一下库级别权限表db,表级别权限表tables_priv表,列级别权限表columns_priv表,理论情况下对于test_table用户只会在mysql.tables_priv表中存在表级别select权限记录,其余权限表不应该有记录,通过下面的查询结果也证实了只有mysql.tables_priv表中存在test_table用户的权限记录
root@localhost : test_grant 12:59:52> select * from mysql.db where user='test_table'\G
Empty set (0.00 sec)
root@localhost : test_grant 01:00:02> select * from mysql.tables_priv where user='test_table'\G
*************************** 1. row ***************************
Host: %
Db: test_grant
User: test_table
Table_name: test_table_grant
Grantor: root@localhost
Timestamp: 0000-00-00 00:00:00
Table_priv: Select # Table_priv列为select表示用户test_table对test_table_grant表具有表级别select权限
Column_priv: # Column_priv列为空表示用户test_table对test_table_grant表不具有列级别权限
1 rows in set (0.00 sec)
root@localhost : test_grant 01:00:17> select * from mysql.columns_priv where user='test_table'\G
Empty set (0.00 sec)
1.4. 查看列级别权限
首先创建一个具对test_table_grant表具有列级别权限的用户test_column,并授予id列的select权限,列级别权限在操作上使用select(column_name)形式 表示,如下
root@localhost : test_grant 01:00:24> grant select(id) on test_grant.test_table_grant to test_column@'%' identified by 'test';
Query OK, 0 rows affected, 1 warning (0.02 sec)
然后,我们查询全局权限表mysql.user发现test_column用户在该表中有记录,但是所有权限标记列为N。确认test_column用户并不具有全局权限,该表中存在着test_column用户的记录是因为要在这里保存密码加密字符串、密码过期时间、账号锁定状态等信息
root@localhost : test_grant 01:02:38> select * from user where user='test_column'\G
ERROR 1146 (42S02): Table 'test_grant.user' doesn't exist
root@localhost : test_grant 01:02:52> select * from mysql.user where user='test_column'\G
*************************** 1. row ***************************
Host: %
User: test_column
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: mysql_native_password
authentication_string: *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
password_expired: N
password_last_changed: 2018-08-19 13:02:38
password_lifetime: NULL
account_locked: N
1 row in set (0.00 sec)
然后我们在查询一下库级别权限表db,表级别权限表tables_priv表,列级别权限表columns_priv表,理论情况下对于test_column用户只会在mysql.tables_priv、mysql.columns_priv表中存在表和列级别select权限记录,其余权限表不应该有记录,通过下面的查询结果也证实了只有mysql.db表中不存在test_column用户的权限记录
root@localhost : test_grant 01:03:02> select * from mysql.db where user='test_column'\G
Empty set (0.00 sec)
root@localhost : test_grant 01:03:08> select * from mysql.tables_priv where user='test_column'\G
*************************** 1. row ***************************
Host: %
Db: test_grant
User: test_column
Table_name: test_table_grant
Grantor: root@localhost
Timestamp: 0000-00-00 00:00:00
Table_priv: # Table_priv列为空表示test_column用户对test_table_grant表不具有表级别权限
Column_priv: Select # Column_priv列为Select表示用户test_column对test_table_grant表具有列级别select权限
1 row in set (0.00 sec)
# 通过对mysql.tables_priv表的查询发现test_column用户对test_table_grant表具有列级别的select权限,由于列级别权限是针对具体的列授予的,这些信息需要通过mysql.columns_priv来查询,如下
root@localhost : test_grant 01:03:23> select * from mysql.columns_priv where user='test_column'\G
*************************** 1. row ***************************
Host: %
Db: test_grant
User: test_column
Table_name: test_table_grant
Column_name: id #对id列有列级别权限
Timestamp: 0000-00-00 00:00:00
Column_priv: Select # 列级别权限为select
1 row in set (0.00 sec)
PS:以上示例中未涉及到的权限管理请自行尝试,这里不再赘述
2、查看统计信息
PS:由于统计信息表的字段含义及其字段值的含义不是很直观,所以下文中列出了统计信息表的字段含义和一些字段值的含义解说内容
2.1. 查看表统计信息
首先创建一张测试表test_stat
root@localhost : (none) 01:41:09> use test
Database changed
root@localhost : test 01:41:13> create table test_stat(id int not null primary key auto_increment);
Query OK, 0 rows affected (0.01 sec)
然后,通过mysql.innodb_table_stats表查看表的统计信息,通过下面的查询信息可以看到,该表最近一次更新统计信息时间为2018-08-19 13:41:46(也是创建表的时间),当前估算数据为0行,有一个页大小的聚集索引。没有其他任何索引
root@localhost : test 01:44:16> select * from mysql.innodb_table_stats where table_name='test_stat'\G
*************************** 1. row ***************************
database_name: test
table_name: test_stat
last_update: 2018-08-19 13:41:46
n_rows: 0
clustered_index_size: 1
sum_of_other_index_sizes: 0
1 row in set (0.00 sec)
表字段含义database_name:数据库名称
-
table_name:表名、分区名或子分区名称
last_update:表示InnoDB上次更新此统计信息行的时间戳
n_rows:表中的估算数据记录行数
clustered_index_size:主键索引的大小,以页为单位的估算数值
sum_of_other_index_sizes:其他(非主键)索引的总大小,以页为单位的估算数值
2.2. 查看索引统计信息
我们这里基于2.1节创建的表进行拓展,我们先通过mysql.innodb_index_stats表查询一下索引统计信息
root@localhost : test 01:44:32> select * from mysql.innodb_index_stats where table_name='test_stat';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | test_stat | PRIMARY | 2018-08-19 13:41:46 | n_diff_pfx01 | 0 | 1 | id |
| test | test_stat | PRIMARY | 2018-08-19 13:41:46 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test_stat | PRIMARY | 2018-08-19 13:41:46 | size | 1 | NULL | Number of pages in the index |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
3 rows in set (0.04 sec)
然后,我们对该表添加2个字段,一个字段创建唯一索引,一个字段创建普通索引
root@localhost : test 01:47:55> alter table test_stat add column test1 int,add unique index i_test1(test1);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
root@localhost : test 02:03:18> alter table test_stat add column test2 int,add index i_test2(test2);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
然后,再次通过mysql.innodb_index_stats表查询索引统计信息,可以发现多了索引i_test1和i_test2的统计信息记录了
root@localhost : test 02:03:33> select * from mysql.innodb_index_stats where table_name='test_stat';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | test_stat | PRIMARY | 2018-08-19 14:03:33 | n_diff_pfx01 | 0 | 1 | id |
| test | test_stat | PRIMARY | 2018-08-19 14:03:33 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test_stat | PRIMARY | 2018-08-19 14:03:33 | size | 1 | NULL | Number of pages in the index |
| test | test_stat | i_test1 | 2018-08-19 14:03:33 | n_diff_pfx01 | 0 | 1 | test1 |
| test | test_stat | i_test1 | 2018-08-19 14:03:33 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test_stat | i_test1 | 2018-08-19 14:03:33 | size | 1 | NULL | Number of pages in the index |
| test | test_stat | i_test2 | 2018-08-19 14:03:33 | n_diff_pfx01 | 0 | 1 | test2 |
| test | test_stat | i_test2 | 2018-08-19 14:03:33 | n_diff_pfx02 | 0 | 1 | test2,id |
| test | test_stat | i_test2 | 2018-08-19 14:03:33 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test_stat | i_test2 | 2018-08-19 14:03:33 | size | 1 | NULL | Number of pages in the index |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
10 rows in set (0.00 sec)
表字段含义
-
database_name:数据库名称
table_name:表名、分区表名、子分区表名称
index_name:索引名称
last_update:表示InnoDB上次更新此统计信息行的时间戳
stat_name:统计信息名称,其对应的统计信息值保存在stat_value列
stat_value:保存统计信息名称stat_name列对应的统计信息值
sample_size:stat_value列中提供的统计信息估计值的采样页数
stat_description:统计信息名称stat_name列中指定的统计信息的说明信息
从表中查询所得的数据中,我们可以看到:
-
stat_name列一种有如下几种统计值
* size:当stat_name为size值时,stat_value列值表示索引中的总页数量
* n_leaf_pages:当stat_name为n_leaf_pages值时,stat_value列值显示索引叶子页的数量
* n_diff_pfxNN:NN代表数字(例如:01,02等),当stat_name为n_diff_pfxNN时,stat_value列值显示索引的first column(即索引的最前索引列,从索引定义顺序的第一个列开始)列的唯一值数量,例如:当NN为01时,stat_value列值就表示索引的第一个列的唯一值数量,当NN为02时,stat_value列值就表示索引的第一和第二个列的组合唯一值数量,以此类推。此外,在stat_name = n_diff_pfxNN的情况下,stat_description列显示一个以逗号分隔的计算索引统计信息列的列表
从index_name为PRIMARY数据行的stat_description列的描述信息"id"中,我们可以看出 ,主键索引的统计信息列只包括创建主键索引时显式指定的列
从index_name为i_test1数据行的stat_description列的描述信息"test1"中,我们可以看出 ,唯一索引的统计信息列只包括创建唯一索引时显式指定的列
从index_name为i_test2数据行的stat_description列的描述信息 " test2,id"中,我们可以看出,普通索引(非唯一的辅助索引)的统计信息列实际上除了定义的索引列之外,还包含了主键列。即对于非唯一索引在该表中记录的统计信息,InnoDB会附加主键列
注意:MySQL 5.7中系统变量innodb_stats_persistent_sample_pages定义的持久化统计信息采样页为20,这里示例中的sample_size列值为1是因为表中数据量太小,在一个页中已经足够存放,所以实际采样也只使用了1个页,如果数据量够多,则这里显示的值就会为innodb_stats_persistent_sample_pages系统变量指定的值
3、查看SQL日志信息
首先,开启会话1,并修改log_output变量为TABLE,修改慢查询日志记录时间为0,启用查询日志和慢查询日志功能
root@localhost : mysql 02:47:28> set global log_output='TABLE';
Query OK, 0 rows affected (0.00 sec)
root@localhost : mysql 02:47:37> set global general_log=1;
Query OK, 0 rows affected (0.00 sec)
root@localhost : mysql 02:47:41> set global slow_query_log=1;
Query OK, 0 rows affected (0.00 sec)
root@localhost : mysql 02:47:45> set global long_query_time=0;
Query OK, 0 rows affected (0.00 sec)
root@localhost : mysql 02:47:50> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 4 |
+-----------------+
1 row in set (0.00 sec)
开启会话2,这里我们基于2.1节中创建的表做进一步拓展,在会话2中对表加锁
root@localhost : (none) 02:48:22> use test
Database changed
root@localhost : test 02:48:23> lock table test_stat read;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 02:48:27> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 9 |
+-----------------+
1 row in set (0.00 sec)
开启会话3,在会话3中对表test_stat插入一行数据
root@localhost : (none) 02:48:55> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 10 |
+-----------------+
1 row in set (0.00 sec)
root@localhost : (none) 02:49:01> use test
Database changed
root@localhost : test 02:49:05> begin;# 显式开启一个事务
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 02:49:06> insert into test_stat values(1,1,1);# 被阻塞
回到会话1中,查询mysql.general_log表和slow_log表
# general_log表
root@localhost : mysql 02:48:03> select * from mysql.general_log;
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
| event_time | user_host | thread_id | server_id | command_type | argument |
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
# 下面是第一个会话设置修改变量的语句
| 2018-08-19 14:47:45.857168 | root[root] @ localhost [] | 4 | 3306111 | Query | set global slow_query_log=1 |
| 2018-08-19 14:47:50.250382 | root[root] @ localhost [] | 4 | 3306111 | Query | set global long_query_time=0 |
| 2018-08-19 14:48:03.434208 | root[root] @ localhost [] | 4 | 3306111 | Query | select connection_id() |
# 下面是第二个会话对test_stat表加锁的语句
| 2018-08-19 14:48:22.284294 | [root] @ localhost [] | 9 | 3306111 | Connect | root@localhost on using Socket |
| 2018-08-19 14:48:22.284637 | root[root] @ localhost [] | 9 | 3306111 | Query | select @@version_comment limit 1 |
| 2018-08-19 14:48:22.289570 | root[root] @ localhost [] | 9 | 3306111 | Query | select USER() |
| 2018-08-19 14:48:23.744586 | root[root] @ localhost [] | 9 | 3306111 | Query | SELECT DATABASE() |
| 2018-08-19 14:48:23.744747 | root[root] @ localhost [] | 9 | 3306111 | Init DB | test |
| 2018-08-19 14:48:27.529909 | root[root] @ localhost [] | 9 | 3306111 | Query | lock table test_stat read |
| 2018-08-19 14:48:39.194290 | root[root] @ localhost [] | 9 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:48:55.444310 | [root] @ localhost [] | 10 | 3306111 | Connect | root@localhost on using Socket |
# 下面是第三个会话显式开启一个事务插入一行数据的语句
| 2018-08-19 14:48:55.444554 | root[root] @ localhost [] | 10 | 3306111 | Query | select @@version_comment limit 1 |
| 2018-08-19 14:48:55.448847 | root[root] @ localhost [] | 10 | 3306111 | Query | select USER() |
| 2018-08-19 14:49:01.473291 | root[root] @ localhost [] | 10 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:49:05.088319 | root[root] @ localhost [] | 10 | 3306111 | Query | SELECT DATABASE() |
| 2018-08-19 14:49:05.088481 | root[root] @ localhost [] | 10 | 3306111 | Init DB | test |
| 2018-08-19 14:49:06.920451 | root[root] @ localhost [] | 10 | 3306111 | Query | begin |
| 2018-08-19 14:49:23.457191 | root[root] @ localhost [] | 10 | 3306111 | Query | insert into test_stat values(1,1,1) |
# 下面是回到会话1查询general_log的语句
| 2018-08-19 14:49:47.280187 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.general_log |
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
19 rows in set (0.00 sec)
# 通过以上数据表明,general_log表中记录的数据是在MySQL Server接收到语句之后一开始执行就立即记录的。现在我们查询一下slow_log表
root@localhost : mysql 02:49:47> select * from mysql.slow_log;
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+----------------------------------+-----------+
| start_time | user_host | query_time | lock_time | rows_sent | rows_examined | db | last_insert_id | insert_id | server_id | sql_text | thread_id |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+----------------------------------+-----------+
| 2018-08-19 14:48:22.284687 | root[root] @ localhost [] | 00:00:00.000083 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select @@version_comment limit 1 | 9 |
| 2018-08-19 14:48:22.289881 | root[root] @ localhost [] | 00:00:00.000379 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select USER() | 9 |
| 2018-08-19 14:48:23.744671 | root[root] @ localhost [] | 00:00:00.000112 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | SELECT DATABASE() | 9 |
| 2018-08-19 14:48:23.744769 | root[root] @ localhost [] | 00:00:00.000035 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | Init DB | 9 |
| 2018-08-19 14:48:27.530057 | root[root] @ localhost [] | 00:00:00.000172 | 00:00:00.000160 | 0 | 0 | test | 0 | 0 | 3306111 | lock table test_stat read | 9 |
| 2018-08-19 14:48:39.194382 | root[root] @ localhost [] | 00:00:00.000126 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | select connection_id() | 9 |
| 2018-08-19 14:48:55.444605 | root[root] @ localhost [] | 00:00:00.000087 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select @@version_comment limit 1 | 10 |
| 2018-08-19 14:48:55.449065 | root[root] @ localhost [] | 00:00:00.000276 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select USER() | 10 |
| 2018-08-19 14:49:01.473380 | root[root] @ localhost [] | 00:00:00.000122 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select connection_id() | 10 |
| 2018-08-19 14:49:05.088409 | root[root] @ localhost [] | 00:00:00.000117 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | SELECT DATABASE() | 10 |
| 2018-08-19 14:49:05.088507 | root[root] @ localhost [] | 00:00:00.000041 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | Init DB | 10 |
| 2018-08-19 14:49:06.920526 | root[root] @ localhost [] | 00:00:00.000091 | 00:00:00.000000 | 0 | 0 | test | 0 | 0 | 3306111 | begin | 10 |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+----------------------------------+-----------+
12 rows in set (0.00 sec)
# 发现slow_log表中此时没有INSERT语句的慢查询记录
现在我们回到会话2进行解锁
root@localhost : test 02:48:39> unlock tables;
Query OK, 0 rows affected (0.00 sec)
现在回到会话3查看INSERT事务执行结果
root@localhost : test 02:49:06> insert into test_stat values(1,1,1);
Query OK, 1 row affected (2 min 12.87 sec)
现在回到会话1查询general_log和slow_log表
# general_log表
root@localhost : mysql 02:50:34> select * from mysql.general_log;
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
| event_time | user_host | thread_id | server_id | command_type | argument |
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
| 2018-08-19 14:47:45.857168 | root[root] @ localhost [] | 4 | 3306111 | Query | set global slow_query_log=1 |
| 2018-08-19 14:47:50.250382 | root[root] @ localhost [] | 4 | 3306111 | Query | set global long_query_time=0 |
| 2018-08-19 14:48:03.434208 | root[root] @ localhost [] | 4 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:48:22.284294 | [root] @ localhost [] | 9 | 3306111 | Connect | root@localhost on using Socket |
| 2018-08-19 14:48:22.284637 | root[root] @ localhost [] | 9 | 3306111 | Query | select @@version_comment limit 1 |
| 2018-08-19 14:48:22.289570 | root[root] @ localhost [] | 9 | 3306111 | Query | select USER() |
| 2018-08-19 14:48:23.744586 | root[root] @ localhost [] | 9 | 3306111 | Query | SELECT DATABASE() |
| 2018-08-19 14:48:23.744747 | root[root] @ localhost [] | 9 | 3306111 | Init DB | test |
| 2018-08-19 14:48:27.529909 | root[root] @ localhost [] | 9 | 3306111 | Query | lock table test_stat read |
| 2018-08-19 14:48:39.194290 | root[root] @ localhost [] | 9 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:48:55.444310 | [root] @ localhost [] | 10 | 3306111 | Connect | root@localhost on using Socket |
| 2018-08-19 14:48:55.444554 | root[root] @ localhost [] | 10 | 3306111 | Query | select @@version_comment limit 1 |
| 2018-08-19 14:48:55.448847 | root[root] @ localhost [] | 10 | 3306111 | Query | select USER() |
| 2018-08-19 14:49:01.473291 | root[root] @ localhost [] | 10 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:49:05.088319 | root[root] @ localhost [] | 10 | 3306111 | Query | SELECT DATABASE() |
| 2018-08-19 14:49:05.088481 | root[root] @ localhost [] | 10 | 3306111 | Init DB | test |
| 2018-08-19 14:49:06.920451 | root[root] @ localhost [] | 10 | 3306111 | Query | begin |
| 2018-08-19 14:49:23.457191 | root[root] @ localhost [] | 10 | 3306111 | Query | insert into test_stat values(1,1,1) |
| 2018-08-19 14:49:47.280187 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.general_log |
| 2018-08-19 14:50:34.591172 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.slow_log |
# 下面是第二个会话解锁的语句
| 2018-08-19 14:51:36.350705 | root[root] @ localhost [] | 9 | 3306111 | Query | unlock tables |
# 下面是第一个会话查询general_log的语句
| 2018-08-19 14:51:58.373666 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.general_log |
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
22 rows in set (0.00 sec)
# slow_log表
root@localhost : mysql 02:51:58> select * from mysql.slow_log;
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-------------------------------------+-----------+
| start_time | user_host | query_time | lock_time | rows_sent | rows_examined | db | last_insert_id | insert_id | server_id | sql_text | thread_id |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-------------------------------------+-----------+
| 2018-08-19 14:48:22.284687 | root[root] @ localhost [] | 00:00:00.000083 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select @@version_comment limit 1 | 9 |
| 2018-08-19 14:48:22.289881 | root[root] @ localhost [] | 00:00:00.000379 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select USER() | 9 |
| 2018-08-19 14:48:23.744671 | root[root] @ localhost [] | 00:00:00.000112 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | SELECT DATABASE() | 9 |
| 2018-08-19 14:48:23.744769 | root[root] @ localhost [] | 00:00:00.000035 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | Init DB | 9 |
| 2018-08-19 14:48:27.530057 | root[root] @ localhost [] | 00:00:00.000172 | 00:00:00.000160 | 0 | 0 | test | 0 | 0 | 3306111 | lock table test_stat read | 9 |
| 2018-08-19 14:48:39.194382 | root[root] @ localhost [] | 00:00:00.000126 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | select connection_id() | 9 |
| 2018-08-19 14:48:55.444605 | root[root] @ localhost [] | 00:00:00.000087 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select @@version_comment limit 1 | 10 |
| 2018-08-19 14:48:55.449065 | root[root] @ localhost [] | 00:00:00.000276 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select USER() | 10 |
| 2018-08-19 14:49:01.473380 | root[root] @ localhost [] | 00:00:00.000122 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select connection_id() | 10 |
| 2018-08-19 14:49:05.088409 | root[root] @ localhost [] | 00:00:00.000117 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | SELECT DATABASE() | 10 |
| 2018-08-19 14:49:05.088507 | root[root] @ localhost [] | 00:00:00.000041 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | Init DB | 10 |
| 2018-08-19 14:49:06.920526 | root[root] @ localhost [] | 00:00:00.000091 | 00:00:00.000000 | 0 | 0 | test | 0 | 0 | 3306111 | begin | 10 |
# 下面是会话2解锁的语句
| 2018-08-19 14:51:36.350840 | root[root] @ localhost [] | 00:00:00.000153 | 00:00:00.000000 | 0 | 0 | test | 0 | 0 | 3306111 | unlock tables | 9 |
# 下面是会话3执行的INSERT慢查询语句
| 2018-08-19 14:51:36.351046 | root[root] @ localhost [] | 00:02:12.893889 | 00:02:12.893718 | 0 | 0 | test | 0 | 0 | 3306111 | insert into test_stat values(1,1,1) | 10 |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-------------------------------------+-----------+
14 rows in set (0.00 sec)
# 注意:此时会话3的事务仍未提交,所以,慢查询日志表中记录的语句与事务无关,只需要语句执行完成即会进行记录
现在回到会话3中,对事务进行提交
root@localhost : test 02:51:36> commit;
Query OK, 0 rows affected (0.01 sec)
现在回到会话1中,分别查询general_log和slow_log表
# general_log表
root@localhost : mysql 02:52:26> select * from mysql.general_log;
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
| event_time | user_host | thread_id | server_id | command_type | argument |
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
| 2018-08-19 14:47:45.857168 | root[root] @ localhost [] | 4 | 3306111 | Query | set global slow_query_log=1 |
| 2018-08-19 14:47:50.250382 | root[root] @ localhost [] | 4 | 3306111 | Query | set global long_query_time=0 |
| 2018-08-19 14:48:03.434208 | root[root] @ localhost [] | 4 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:48:22.284294 | [root] @ localhost [] | 9 | 3306111 | Connect | root@localhost on using Socket |
| 2018-08-19 14:48:22.284637 | root[root] @ localhost [] | 9 | 3306111 | Query | select @@version_comment limit 1 |
| 2018-08-19 14:48:22.289570 | root[root] @ localhost [] | 9 | 3306111 | Query | select USER() |
| 2018-08-19 14:48:23.744586 | root[root] @ localhost [] | 9 | 3306111 | Query | SELECT DATABASE() |
| 2018-08-19 14:48:23.744747 | root[root] @ localhost [] | 9 | 3306111 | Init DB | test |
| 2018-08-19 14:48:27.529909 | root[root] @ localhost [] | 9 | 3306111 | Query | lock table test_stat read |
| 2018-08-19 14:48:39.194290 | root[root] @ localhost [] | 9 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:48:55.444310 | [root] @ localhost [] | 10 | 3306111 | Connect | root@localhost on using Socket |
| 2018-08-19 14:48:55.444554 | root[root] @ localhost [] | 10 | 3306111 | Query | select @@version_comment limit 1 |
| 2018-08-19 14:48:55.448847 | root[root] @ localhost [] | 10 | 3306111 | Query | select USER() |
| 2018-08-19 14:49:01.473291 | root[root] @ localhost [] | 10 | 3306111 | Query | select connection_id() |
| 2018-08-19 14:49:05.088319 | root[root] @ localhost [] | 10 | 3306111 | Query | SELECT DATABASE() |
| 2018-08-19 14:49:05.088481 | root[root] @ localhost [] | 10 | 3306111 | Init DB | test |
| 2018-08-19 14:49:06.920451 | root[root] @ localhost [] | 10 | 3306111 | Query | begin |
| 2018-08-19 14:49:23.457191 | root[root] @ localhost [] | 10 | 3306111 | Query | insert into test_stat values(1,1,1) |
| 2018-08-19 14:49:47.280187 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.general_log |
| 2018-08-19 14:50:34.591172 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.slow_log |
| 2018-08-19 14:51:36.350705 | root[root] @ localhost [] | 9 | 3306111 | Query | unlock tables |
| 2018-08-19 14:51:58.373666 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.general_log |
| 2018-08-19 14:52:26.182895 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.slow_log |
# 下面是会话3执行的显式commit语句
| 2018-08-19 14:54:14.339269 | root[root] @ localhost [] | 10 | 3306111 | Query | commit |
# 下面是会话1查询general_log表的语句
| 2018-08-19 14:54:23.637580 | root[root] @ localhost [] | 4 | 3306111 | Query | select * from mysql.general_log |
+----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------+
25 rows in set (0.00 sec)
# slow_log表
root@localhost : mysql 02:54:23> select * from mysql.slow_log;
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-------------------------------------+-----------+
| start_time | user_host | query_time | lock_time | rows_sent | rows_examined | db | last_insert_id | insert_id | server_id | sql_text | thread_id |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-------------------------------------+-----------+
| 2018-08-19 14:48:22.284687 | root[root] @ localhost [] | 00:00:00.000083 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select @@version_comment limit 1 | 9 |
| 2018-08-19 14:48:22.289881 | root[root] @ localhost [] | 00:00:00.000379 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select USER() | 9 |
| 2018-08-19 14:48:23.744671 | root[root] @ localhost [] | 00:00:00.000112 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | SELECT DATABASE() | 9 |
| 2018-08-19 14:48:23.744769 | root[root] @ localhost [] | 00:00:00.000035 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | Init DB | 9 |
| 2018-08-19 14:48:27.530057 | root[root] @ localhost [] | 00:00:00.000172 | 00:00:00.000160 | 0 | 0 | test | 0 | 0 | 3306111 | lock table test_stat read | 9 |
| 2018-08-19 14:48:39.194382 | root[root] @ localhost [] | 00:00:00.000126 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | select connection_id() | 9 |
| 2018-08-19 14:48:55.444605 | root[root] @ localhost [] | 00:00:00.000087 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select @@version_comment limit 1 | 10 |
| 2018-08-19 14:48:55.449065 | root[root] @ localhost [] | 00:00:00.000276 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select USER() | 10 |
| 2018-08-19 14:49:01.473380 | root[root] @ localhost [] | 00:00:00.000122 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | select connection_id() | 10 |
| 2018-08-19 14:49:05.088409 | root[root] @ localhost [] | 00:00:00.000117 | 00:00:00.000000 | 1 | 0 | | 0 | 0 | 3306111 | SELECT DATABASE() | 10 |
| 2018-08-19 14:49:05.088507 | root[root] @ localhost [] | 00:00:00.000041 | 00:00:00.000000 | 1 | 0 | test | 0 | 0 | 3306111 | Init DB | 10 |
| 2018-08-19 14:49:06.920526 | root[root] @ localhost [] | 00:00:00.000091 | 00:00:00.000000 | 0 | 0 | test | 0 | 0 | 3306111 | begin | 10 |
| 2018-08-19 14:51:36.350840 | root[root] @ localhost [] | 00:00:00.000153 | 00:00:00.000000 | 0 | 0 | test | 0 | 0 | 3306111 | unlock tables | 9 |
| 2018-08-19 14:51:36.351046 | root[root] @ localhost [] | 00:02:12.893889 | 00:02:12.893718 | 0 | 0 | test | 0 | 0 | 3306111 | insert into test_stat values(1,1,1) | 10 |
# 下面是会话3执行的COMMIT语句
| 2018-08-19 14:54:14.341319 | root[root] @ localhost [] | 00:00:00.002071 | 00:00:00.000000 | 0 | 0 | test | 0 | 0 | 3306111 | commit | 10 |
+----------------------------+---------------------------+-----------------+-----------------+-----------+---------------+------+----------------+-----------+-----------+-------------------------------------+-----------+
15 rows in set (0.00 sec)
注意事项:综上所述,查询日志会在语句一开始执行的时候就进行记录,而慢查询语句会在语句执行完成并释放完所有的锁之后进行记录,两者记录语句都与事务是否提交无关。
-
很多人说慢查询日志的执行时间不包括锁等待时间(其实很多人搞混淆了,正确的说法是,一个语句是否判定为慢查询,是看执行时间是否超过系统变量long_query_time的值,而语句执行时间不包括锁等待时间指的是:与long_query_time变量值比较的语句执行时间值中是不包括锁等待时间的,而不是说记录在慢查询日志中的语句执行时间不包括锁等待时间),通过显式在会话2中加表锁以及后续在会话2中加事务锁和全局读锁时,在会话3中的DML语句执行完之后记录的慢查询日志中也证实了它总是包含了锁等待时间的(也测试过log_output=FILE,结果一样)
* 举个例子:就拿我们上面示例来说,如果把long_query_time变量设置为1(表示执行时间超过1S就记录为慢查询),你就会发现无论INSERT语句被其他语句的锁阻塞多久,都不会记录到慢查询日志中(因为INSERT语句插入一行记录的执行时间排除了锁等待时间之外,真正的执行时间超过1S的情况微乎其微)
坚持阅读我们的"全方位认识 mysql 系统库"系列文章分享,你就可以系统地学完它。截止目前为止,MySQL的4个系统库"performance_schema"、"information_schema"、"sys"、"mysql"我们已经通过4个系列文章为大家介绍完毕。如果你觉得对你有帮助或者你认为有学习与传播的价值,欢迎分享给他人。后续我们将择期推出MySQL优化与复制板块的系列文章。谢谢你的阅读,我们下期不见不散!
| 作者简介
罗小波·ScaleFlux数据库技术专家
《千金良方——MySQL性能优化金字塔法则》、《数据生态:MySQL复制技术与生产实践》作者之一。
熟悉MySQL体系结构,擅长数据库的整体调优,喜好专研开源技术,并热衷于开源技术的推广,在线上线下做过多次公开的数据库专题分享,发表过近100篇数据库相关的研究文章。
全文完。
Enjoy MySQL :)
叶老师的「MySQL核心优化」大课已升级到MySQL 8.0,扫码开启MySQL 8.0修行之旅吧
来源:oschina
链接:https://my.oschina.net/u/4323802/blog/4776218