一、日志相关简介
日志记录了MySQL数据库日常操作和错误信息。MySQL有不同类型的日志文件(各自存储了不同类型的日志),从日志当中可以查询到MySQL数据库的运行情况、用户的操作、错误的信息等。
1.MySQL日志分为4大类
(1)错误日志:记录mysql服务的启动,运行或停止时出现的问题;
(2)查询日志:记录建立的客户端连接和执行的语句;
(3)二进制日志:记录所有更改数据的语句,可以用于数据的复制;
(4)慢查询日志:记录所有执行时间超过long_query_time的所有查询或不使用索引的查询;
默认情况下,所有日志创建于MySQL数据目录中,通过刷新日志,可以强制MySQL关闭和重新打开日志文件,Flush logs刷新日志或者执行mysqladmin flush-logs。如果正使用MySQL复制功能,在复制服务器上可以维护更多日志文件,这种日志称为接替日志。启动日志功能会降低MySQL数据库的性能。
二、错误日志
在mysql数据库中,错误日志功能是默认开启的。默认情况下,错误日志存储在mysql数据库的数据目录中。错误日志文件通常的名称为hostname.err。其中,hostname表示服务器主机名。错误日志信息可以自己进行配置,错误日志所记录的信息是可以通过log-error和log-warnings来定义的,其中log-error是定义是否启用错误日志的功能和错误日志的存储位置,log-warnings是定义是否将警告信息也定义至错误日志中。
1.默认情况下错误日志大致记录以下几个方面的信息
(1)服务器启动和关闭过程中的信息(未必是错误信息,如mysql如何启动InnoDB的表空间文件的、如何初始化自己的存储引擎等);
(2)服务器运行过程中的错误信息;
(3)事件调度器运行一个事件时产生的信息;
(4)在从服务器上启动服务器进程时产生的信息;
注意
:MySQL有很多系统变量可以设置,系统变量设置不同,会导致系统运行状态的不同。因此mysql提供两组命令,分别查看系统设置和运行状态。
2.查看系统设置
SHOW [GLOBAL | SESSION] VARIABLES
[LIKE 'pattern' | WHERE expr]
SHOW [GLOBAL | SESSION] VARIABLES [like_or_where]
SHOW VARIABLES: shows the values of MySQL system variables.
3.查看运行状态
SHOW [GLOBAL | SESSION] STATUS
[LIKE 'pattern' | WHERE expr]
SHOW [GLOBAL | SESSION] STATUS [like_or_where]
SHOW STATUS: provides server status information.
4.如何修改系统配置
方法1:配置文件设置my.cnf。如:binlog_cache_size = 1M
方法2:set global binlog_cache_size = 1048576;
注意
:查看mysql的版本
[root@localhost ~]# mysql -V
mysql Ver 14.14 Distrib 5.7.32, for linux-glibc2.12 (x86_64) using EditLine wrapper
或
mysql> status; #或者mysql> \s;
--------------
mysql Ver 14.14 Distrib 5.7.32, for linux-glibc2.12 (x86_64) using EditLine wrapper
Connection id: 4
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.32 MySQL Community Server (GPL)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /tmp/mysql.sock
Uptime: 1 hour 51 min 37 sec
Threads: 1 Questions: 13 Slow queries: 0 Opens: 109 Flush tables: 1 Open tables: 102 Queries per second avg: 0.001
--------------
或
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.32 |
+-----------+
1 row in set (0.00 sec)
一般而言,日志级别的定义没有会话变量都只是在全局级别下进行定义错误日志的状态:
mysql> show global variables like '%log_error%';
+---------------------+----------------------------------+
| Variable_name | Value |
+---------------------+----------------------------------+
| binlog_error_action | ABORT_SERVER |
| log_error | /usr/local/mysql/data/mysqld.err |
| log_error_verbosity | 3 |
+---------------------+----------------------------------+
3 rows in set (0.01 sec)
其中log_error定义为错误日志文件路径
log_error_verbosity有如下三种级别:
Verbosity Value | Message Types Logged |
---|---|
1 | Errors only |
2 | Errors and warnings |
3 | Errors, warnings, and notes(default) |
更改错误日志位置可以使用log-error来设置:
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
pid-file=/usr/local/mysql/data/mysqld.pid
log-error=/usr/local/mysql/data/mysqld.err
socket=/tmp/mysql.sock
查看mysql错误日志
[root@localhost ~]# tail -f /usr/local/mysql/data/mysqld.err
为了方便维护,有时会将错误日志中的内容做备份并重新开始记录,这时就可以利用MySQL的FLUSH LOGS命令来告诉MySQL备份旧日志文件并生成新的日志文件。备份文件名以“.old”结尾。
5.删除错误日志
(1)在mysql5.5.7之前
数据库管理员可以删除很长时间之前的错误日志,以保证mysql服务器上的硬盘空间。mysql数据库中,可以使用mysqladmin命令开启新的错误日志。
mysqladmin命令的语法如下:
[root@localhost ~]# mysqladmin –uroot –pasd123 flush-logs
也可以登录mysql数据库中使用FLUSH LOGS语句来开启新的错误日志。
(2)在mysql5.5.7之后
服务器将关闭此项功能。只能使用重命名原来的错误日志文件,手动冲洗日志创建一个新的。
方式如下:
[root@localhost ~]# cd /usr/local/mysql/data
[root@localhost data]# mv mysqld.err mysqld.old
[root@localhost data]# mysqladmin -uroot -pasd123 flush-logs
更多信息请查阅官方文档
http://dev.mysql.com/doc/refman/5.5/en/error-log.html
http://dev.mysql.com/doc/refman/5.6/en/error-log.html http://dev.mysql.com/doc/refman/5.7/en/error-log.html
三、二进制日志
主要记录MySQL数据库的变化,二进制日志以一种有效的格式,并且是事务安全的方式包含更新日志中可用的信息。二进制日志包含所有更新的数据或者已经潜在更新的数据。二进制日志还包含关于每个更新数据库的语句的执行时间,它不包含没有修改任何数据的语句。使用二进制日志的主要目的是最大可能地恢复数据库。
启动二进制日志,默认情况下二进制日志是关闭的。
1.编辑配置文件My.ini或my.cnf
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
pid-file=/usr/local/mysql/data/mysqld.pid
log-error=/usr/local/mysql/data/mysqld.err
socket=/tmp/mysql.sock
log-bin = mysql-bin #打开二进制日志,后面是名字。
server-id = 1 #必须和log-bin搭配才可以生效。
expire_logs_days = 10 #清除日志的天数
max_binlog_size 100M #单个日志文件的大小限制,超出会新建一个默认为1GB
[root@localhost ~]# systemctl restart mysqld
2.查询日志设置
mysql> show variables like 'log_%';
+----------------------------------------+---------------------------------------+
| Variable_name | Value |
+----------------------------------------+---------------------------------------+
| log_bin | ON |
| log_bin_basename | /usr/local/mysql/data/mysql-bin |
| log_bin_index | /usr/local/mysql/data/mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| log_builtin_as_identified_by_password | OFF |
| log_error | /usr/local/mysql/data/mysqld.err |
| log_error_verbosity | 3 |
| log_output | FILE |
| log_queries_not_using_indexes | OFF |
| log_slave_updates | OFF |
| log_slow_admin_statements | OFF |
| log_slow_slave_statements | OFF |
| log_statements_unsafe_for_binlog | ON |
| log_syslog | OFF |
| log_syslog_facility | daemon |
| log_syslog_include_pid | ON |
| log_syslog_tag | |
| log_throttle_queries_not_using_indexes | 0 |
| log_timestamps | UTC |
| log_warnings | 2 |
+----------------------------------------+---------------------------------------+
21 rows in set (0.00 sec)
3.查看二进制日志
MySQL二进制日志存储了所有的变更信息,MySQL二进制日志经常使用。当MySQL创建二进制日志文件时,首先创建一个以’filename’为名称,以’.index’为后缀的文件;再创建一个以’filename’为名称,以’.000001’为后缀的文件。当MySQL服务重启一次,以’.000001’为后缀的文件会增加一个,并且后缀名加1递增。如果日志长度超过max_binlog_size的上限,也会创建一个新的日志。
可以使用命令show binary logs查看当前的二进制日志文件个数及其文件名。
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 201 |
| mysql-bin.000002 | 154 |
+------------------+-----------+
2 rows in set (0.00 sec)
4.查看二进制日志的内容
[root@localhost data]# mysqlbinlog mysql-bin.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#201231 16:07:25 server id 1 end_log_pos 123 CRC32 0x4ffefd98 Start: binlog v 4, server v 5.7.32-log created 201231 16:07:25 at startup
ROLLBACK/*!*/;
BINLOG '
vYbtXw8BAAAAdwAAAHsAAAAAAAQANS43LjMyLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAC9hu1fEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AZj9/k8=
'/*!*/;
# at 123
#201231 16:07:25 server id 1 end_log_pos 154 CRC32 0xc234c68b Previous-GTIDs
# [empty]
# at 154
#201231 16:07:48 server id 1 end_log_pos 201 CRC32 0x3fe4be32 Rotate to mysql-bin.000002 pos: 4
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*/;
5.删除二进制日志
MySQL的二进制文件可以配置自动删除,同时MySQL提供了手动删除二进制文件的方法。
语法格式
PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }
RESET { MASTER | QUERY CACHE | SLAVE}
reset master; #删除所有二进制日志,并生成第一位的一个新的二进制文件;
purge master logs to ‘二进制文件名’ #删除某个二进制日志之前的日志;
purge master logs before 'date' #删除某个二进制日志创建时间之前的日志,如果时间包括所有则保留最后一个;
示例
mysql> purge master logs to 'mysql-bin.000003';
Query OK, 0 rows affected (0.00 sec)
mysql> purge master logs before '2020-12-31 16:23:10';
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
6.还原
如果MySQL服务器启用了二进制日志,使用二进制日志还原数据库。使用最后一次备份还原或指定一个时间恢复数据。
语法格式
mysqlbinlog [option] filename mysql –uuser -ppassword
[option]里面的选项
--start-datetime #开始的时间
--stop-datetime #结束的时间
--stop-position #结束的位置
示例
[root@mysql data]# mysqlbinlog mysql-bin.0000010 mysql -u root -pasd123
mysqlbinlog: [Warning] Using a password on the command line interface can be insecure.
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
mysqlbinlog: File 'mysql-bin.0000010' not found (Errcode: 2 - No such file or directory)
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*/;
7.暂时停止二进制日志的功能
如果MySQL的配置文件已经启动了二进制日志,MySQL会一直记录二进制日志,修改配置文件,可以停止二进制日志,但是需要重启MySQL数据库。MySQL提供了暂时停止二进制日志的功能,通过SET SQL_LOG_BIN语句可以暂时停止二进制日志。
mysql> show variables like '%log_bin%';
+---------------------------------+---------------------------------------+
| Variable_name | Value |
+---------------------------------+---------------------------------------+
| log_bin | ON |
| log_bin_basename | /usr/local/mysql/data/mysql-bin |
| log_bin_index | /usr/local/mysql/data/mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+---------------------------------------+
6 rows in set (0.00 sec)
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%log_bin%';
+---------------------------------+---------------------------------------+
| Variable_name | Value |
+---------------------------------+---------------------------------------+
| log_bin | ON |
| log_bin_basename | /usr/local/mysql/data/mysql-bin |
| log_bin_index | /usr/local/mysql/data/mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | OFF |
+---------------------------------+---------------------------------------+
6 rows in set (0.00 sec)
四、事务日志(redo log和undo log)
事务日志(InnoDB特有的日志)可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。事务日志采用追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序I/O,而不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多。事务日志持久以后,内存中被修改的数据在后台可以慢慢的刷回到磁盘。目前大多数的存储引擎都是这样实现的。如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。具有的恢复方式则视存储引擎而定。
事务日志级别设置
设置为1(默认值)时:事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。
这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
设置为0时:事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。
也就是说是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。
设置为2时,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。
1.查看事务日志的定义
mysql> show global variables like '%innodb_flush_log%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_timeout | 1 |
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
2 rows in set (0.00 sec)
参数解释
(1)innodb_flush_log_at_timeout=1
刷新日志的超时时间
(2)innodb_flush_log_at_trx_commit=1
在事务提交时innodb是否同步日志从缓冲区到文件中。
当这个值为1(默认值)时,在每个事务提交时,日志缓冲被写到日志文件,对日志文件做到磁盘操作的刷新,性能会很差造成大量的磁盘I/O,但这种方式最安全;
如果设为2时,每次提交事务都会写日志,但并不会执行刷新的操作。每秒定时会刷新到日志文件。要注意的是,并不能保证100%每秒一定都会刷到磁盘,这要取决于进程的调度。每次事务提交的时候将数据写入事务日志,而这里的写入仅是调用了文件系统的写入操作,而文件系统是有缓存的,所以这个写入并不能保证数据已经写入到物理磁盘。
设置为0,日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新,但是在一个事务提交不做任何操作。
注意刷写的概念
刷写其实是两个操作,刷(flush)和写(write),区分这两个概念是很重要的。
在大多数的操作系统中,把Innodb的log buffer(内存)写入日志(调用系统用write),只是简单的把数据移到操作系统缓存中,操作系统缓存同样指的是内存。并没有实际的持久化数据。所以,通常设为0和2的时候,在系统崩溃或断电的时候会丢失最后一秒的数据,因为这个时候数据只是存在于操作系统缓存。之所以说“通常”,可能会有丢失不只1秒的数据的情况,比如说执行flush操作的时候阻塞了。
总结
设为1当然是最安全的,但性能页是最差的(相对其他两个参数而言,但不是不能接受)。
如果对数据一致性和完整性要求不高,完全可以设为2。
如果只要求性能,例如高并发写的日志服务器,设为0来获得更高性能。
(3)innodb_log_file_size=50331648
日志文件大小
(4)innodb_log_files_in_group=2
DB中设置几组事务日志,默认是2
(5)innodb_log_group_home_dir=./
定义innodb事务日志组的位置,此位置设置默认为MySQL的datadir。
每个事务日志都是大小为50兆的文件(不同版本的mysql有差异)。
在mysql中默认以ib_logfile0,ib_logfile1名称存在。
(6)innodb_io_capacity=2000
设置脏页刷新速度,单位为页。磁盘速度越快就设置越大,建议和磁盘IOPS一样。
(7)innodb_flush_neighbors=0
刷脏页时是否把数据页旁边的脏页也刷掉,1为一起刷,SSD磁盘建议为0,8.0开始默认为0。
2.undo log作用
undo log记录了每个事务的反向操作,当数据库发生异常错误时可以根据undo log回滚到事务之前的数据状态,保证了事务的原子性。另外MVCC特性也是通过undo log来计算出历史版本的数据。undo log会写入到ibdata和ibtmp文件中。当数据库重启进行crash-recovery时会通过redo log将已经提交事务的更改写到数据文件,而还没有提交的就通过undo log进行roll back。
3.undo log相关参数配置
(1)innodb_data_home_dir=/data/mysql/
共享表空间文件存放路径,文件名为ibdata1。
(2)innodb_data_file_path=ibdata1:1024M:autoextend
共享表空间文件大小,可以写多个文件进行拆分。
五、慢查询日志(slow query log)
慢查询日志用于记录那些已经执行完成但是执行时间过慢的DML语句(也可以通过配置打开DDL语句的记录),这些被记录的语句都是自身执行过慢的语句,而不包含锁等待时间。
慢查询日志采用的是简单的文本格式,可以通过各种文本编辑器查看其中的内容。其中记录了语句执行的时刻,执行所消耗的时间,执行用户,连接主机等相关信息。
慢查询之所以会出现基本上归咎于两点:查询语句过于复杂、索引覆盖不全。
1.慢查询日志的作用
可以查找出哪些查询语句的执行效率较低,以便进行优化。一般建议开启,它对服务器性能的影响微乎其微,但是可以记录mysql服务器上执行了很长时间的查询语句。可以帮助我们定位性能问题。MySQL还提供了专门用来分析慢查询日志的工具程序mysqldumpslow,用来帮助数据库管理人员解决可能存在的性能问题。
数据库性能问题大多数都是由于慢查询语句导致,大量慢查询并发出现时会导致服务器CPU跑高的情况发生,所以慢查询日志可以帮助管理员分析问题所在,起到对SQL进行优化的作用。
优化通常从高到低逐步进行,比如一开始定义超过5秒的算慢语句,然后等把这部分5秒的慢语句都处理完了再降低到4秒,以此类推。在一个慢查询日志中最需要关注执行次数多、执行时间长、IO过高、未命中索引的SQL。
2.查看慢查询日志的定义
mysql> show global variables like '%slow_query_log%';
+---------------------+--------------------------------------+
| Variable_name | Value |
+---------------------+--------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /usr/local/mysql/data/mysql-slow.log |
+---------------------+--------------------------------------+
2 rows in set (0.00 sec)
mysql> show global variables like '%long%';
+----------------------------------------------------------+-----------+
| Variable_name | Value |
+----------------------------------------------------------+-----------+
| long_query_time | 10.000000 |
| performance_schema_events_stages_history_long_size | 10000 |
| performance_schema_events_statements_history_long_size | 10000 |
| performance_schema_events_transactions_history_long_size | 10000 |
| performance_schema_events_waits_history_long_size | 10000 |
+----------------------------------------------------------+-----------+
5 rows in set (0.00 sec)
3.启动和设置慢查询日志
(1)通过配置文件my.cnf开启慢查询日志
注意
:在不同的mysql版本中,开启慢查询日志参数不太一样,不过都可以通过show variables like “%slow%” 和show variables like “%long%”查看。
mysql> show global variables like '%slow%';
+---------------------------+--------------------------------------+
| Variable_name | Value |
+---------------------------+--------------------------------------+
| log_slow_admin_statements | OFF |
| log_slow_slave_statements | OFF |
| slow_launch_time | 2 |
| slow_query_log | OFF |
| slow_query_log_file | /usr/local/mysql/data/mysql-slow.log |
+---------------------------+--------------------------------------+
5 rows in set (0.00 sec)
参数解释
slow_query_log #off关闭状态 on开启状态
slow_query_log_file #慢查询日志存放地点
long_query_time #设置一个时间值,时间以秒为单位,可以精确到微秒。如果查询时间超过了这个值(默认为10秒),这个查询语句将被记录到慢查询日志中,设置为0的话表示记录所有的查询。
slow_launch_time #表示如果建立线程花费了比这个值更长的时间。
slow_launch_threads #计数器将增加。注:如果不指定存储路径,慢查询日志默认存储到mysql数据库的数据文件下,如果不指定文件名,默认文件名为hostname-slow.log。
修改my.cnf文件
[mysqld]
slow_query_log = 1 #开启慢查询日志
slow_query_log_file = /usr/local/mysql/data/mysql-slow.log #指定日志文件保存路径,不指定的话默认在数据库文件目录下,名为hostname-slow.log
long_query_time = 2 #指定达到多少秒才算慢查询,设为0代表记录所有查询
log_queries_not_using_indexes = 1 #如果语句没有使用索引也会被记录,即便没有达到阈值
log_throttle_queries_not_using_indexes=60 #如果没有使用索引的SQL执行特别频繁,那每分钟最多只记录60次
log_timestamps = system #默认为UTC时间,这样查看日志会存在时区问题,建议修改为SYSTEM,和系统时间一致
# min_examined_row_limit = 1000 #SQL至少要扫描达到指定的行数才记录
# log-slow-admin-statements #记录由ALTER TABLE等语句引发的慢查询
# log-slow-slave-statements #记录从服务器产生的慢查询
slow_launch_time=1
重启mysqld服务,再次查询慢查询日志定义。
(2)通过登录mysql服务器直接定义
mysql> set global slow_query_log=1; #开启慢查询日志
Query OK, 0 rows affected (0.00 sec)
mysql> set session long_query_time=0.0001; #更改时间(当前session中,退出则重置)
Query OK, 0 rows affected (0.00 sec)
mysql> set global long_query_time=0.0001; #更改时间(全局中,重启服务则重置)
Query OK, 0 rows affected (0.00 sec)
mysql> show global variables like '%long%'; #查询定义时间
+----------------------------------------------------------+----------+
| Variable_name | Value |
+----------------------------------------------------------+----------+
| long_query_time | 0.000100 |
| performance_schema_events_stages_history_long_size | 10000 |
| performance_schema_events_statements_history_long_size | 10000 |
| performance_schema_events_transactions_history_long_size | 10000 |
| performance_schema_events_waits_history_long_size | 10000 |
+----------------------------------------------------------+----------+
5 rows in set (0.00 sec)
4.查看慢查询日志
mysql> use mysql
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> select sleep(3);
+----------+
| sleep(3) |
+----------+
| 0 |
+----------+
1 row in set (3.00 sec)
cat直接查看慢日志文件
[root@localhost data]# cat mysql-slow.log
/usr/local/mysql/bin/mysqld, Version: 5.7.32-log (MySQL Community Server (GPL)). started with:
Tcp port: 0 Unix socket: /tmp/mysql.sock
Time Id Command Argument
# Time: 2021-01-17T20:00:57.111884+08:00
# User@Host: root[root] @ localhost [] Id: 2
# Query_time: 3.002390 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0
SET timestamp=1610884857;
select sleep(3);
慢查询产生的原因一般是lock_time锁等待时间太长,或者是examined处理的数据太多导致。
第一行表示记录日志时的时间。其格式是YYYY-MM-DD HH:MM:SS。
注意
:这个是服务器时间。
MySql用户、服务器以及主机名第三行表示总的查询时间、锁定时间、”发送”或者返回的行数。
Query_time:表示查询使用的时间。
Lock_time:表示锁了多长时间。
Rows_sent:表示返回的行数。
Rows_examined:表示一共查了多少行。
SET timestamp=UNIXTIME:这是查询实际发生的时间,将Unix时间转成一个可读的时间,可以使用命令date –date=’@2147483647’,日志中的时间戳以看到查询进行的同时记录了该日志,但是对于一台超负载的服务器常常并非如此。因此SET timestamp = value才是实际查询的执行时间。
慢查询分析mysqldumpslow可以通过打开log文件查看得知哪些SQL执行效率低下。从日志中,可以发现查询时间超过long_query_time时间的query为慢查询,而小于long_query_time时间的没有出现在此日志中。如果慢查询日志中记录内容很多,可以使用mysqldumpslow工具对慢查询日志进行分类汇总。
mysqldumpslow对日志文件进行了分类汇总,显示汇总后摘要结果。
[root@localhost data]# mysqldumpslow mysql-slow.log
Reading mysql slow query log from mysql-slow.log
Count: 1 Time=3.00s (3s) Lock=0.00s (0s) Rows=1.0 (1), root[root]@localhost
select sleep(N)
注意
:
mysqldumpslow -s c -t 10 /database/mysql/slow-query.log
#这会输出记录次数最多的10条SQL语句。
参数解释
-s:是表示按照何种方式排序。
c、t、l、r分别是按照记录次数、查询时间、锁时间、返回的记录行数来排序;
at、al、ar,表示相应的平均值;
-t:是top n的意思,即为返回前面多少条的数据;
-g:后边可以写一个正则匹配模式,大小写不敏感的;
例如
mysqldumpslow -s r -t 10 /database/mysql/slow-log
#得到返回记录集最多的10个查询。
mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log
#得到按照时间排序的前10条里面含有左连接的查询语句。
5.慢日志分析方法pt-query-digest
(1)pt-query-digest命令执行(由percona-toolkit软件包所提供)。
percona-toolkit下载
[root@localhost ~]# ls
percona-toolkit-3.3.0-1.el7.x86_64.rpm
[root@localhost ~]# yum -y localinstall percona-toolkit-3.3.0-1.el7.x86_64.rpm
[root@localhost data]# pt-query-digest mysql-slow.log
# 150ms user time, 30ms system time, 26.12M rss, 224.61M vsz
# Current date: Sun Jan 17 21:20:27 2021
# Hostname: localhost.localdomain
# Files: mysql-slow.log
# Overall: 1 total, 1 unique, 0 QPS, 0x concurrency ______________________
# Time range: all events occurred at 2021-01-17T20:00:57
# Attribute total min max avg 95% stddev median
# ============ ======= ======= ======= ======= ======= ======= =======
# Exec time 3s 3s 3s 3s 3s 0 3s
# Lock time 0 0 0 0 0 0 0
# Rows sent 1 1 1 1 1 0 1
# Rows examine 0 0 0 0 0 0 0
# Query size 15 15 15 15 15 0 15
# Profile
# Rank Query ID Response time Calls R/Call V/M
# ==== =================================== ============= ===== ====== ====
# 1 0x59A74D08D407B5EDF9A57DD5A41825CA 3.0024 100.0% 1 3.0024 0.00 SELECT
# Query 1: 0 QPS, 0x concurrency, ID 0x59A74D08D407B5EDF9A57DD5A41825CA at byte 0
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.00
# Time range: all events occurred at 2021-01-17T20:00:57
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 100 1
# Exec time 100 3s 3s 3s 3s 3s 0 3s
# Lock time 0 0 0 0 0 0 0 0
# Rows sent 100 1 1 1 1 1 0 1
# Rows examine 0 0 0 0 0 0 0 0
# Query size 100 15 15 15 15 15 0 15
# String:
# Hosts localhost
# Users root
# Query_time distribution
# 1us
# 10us
# 100us
# 1ms
# 10ms
# 100ms
# 1s ################################################################
# 10s+
# EXPLAIN /*!50100 PARTITIONS*/
select sleep(3)\G
#分析最近12个小时的慢查询
[root@localhost data]# pt-query-digest --since=12h mysql-slow.log
#指定时间范围进行分析
[root@localhost data]# pt-query-digest --since '2021-01-10 12:00:00' --until '2021-01-11 12:00:00' mysql-slow.log
(2)pt-query-digest执行结果
第一部分总体统计数据
在这部分中重点关注Overall所展示的数据信息,它包含了指定时间范围内的查询总数、唯一查询数量(有多少个不同的SQL)、QPS、并发数。
Overall: 1 total, 1 unique, 0 QPS, 0x concurrency
第二部分分组统计数据
Rank:所有语句的排名,默认按查询时间降序排列,通过–order-by指定。
Response:总的响应时间。
time:该查询在本次分析中总的时间占比。
calls:执行次数,即本次分析总共有多少条这种类型的查询语句。
R/Call:平均每次执行的响应时间。
V/M:响应时间Variance-to-mean的比率。
Item:查询对象。
第三部分详细统计结果
列出了上一部分中排行靠前的SQL的执行次数、最大耗时、最小耗时、平均耗时、95%耗时等统计信息。
Databases:数据库名。
Users:各个用户执行的次数(占比)。
Query_time distribution :查询时间分布, 长短体现区间占比,本例中1s-10s之间查询数量是10s以上的两倍。
Tables:查询中涉及到的表。
Explain:SQL语句。
(3)查看执行计划
从慢日志中获取到具体SQL后,可以结合explain执行计划进行进一步的分析。
六、数据文件
在MySQL中每一个数据库都会在定义好(或者默认)的数据目录下存在一个以数据库名字命名的文件夹,用来存放该数据库中各种表数据文件。不同的存储引擎有各自不同的数据文件。如MyISAM用“.MYD”作为扩展名,Innodb用“.ibd”,Archive用“.arc”,CSV用“.csv”等等。
1.创建一个数据库并在数据库中创建一个表
mysql> create database testdb;
Query OK, 1 row affected (0.00 sec)
mysql> use testdb;
Database changed
mysql> create table a (a int,b int);
Query OK, 0 rows affected (0.01 sec)
2.查看数据库所在目录
发现数据目录下存在一个以数据库名字命名的文件夹。
[root@localhost data]# ls
auto.cnf ib_buffer_pool localhost-slow.log private_key.pem testdb
ca-key.pem ibdata1 mysql public_key.pem
ca.pem ib_logfile0 mysqld.err server-cert.pem
client-cert.pem ib_logfile1 mysqld.pid server-key.pem
client-key.pem ibtmp1 performance_schema sys
3.查看testdb目录的文件列表
[root@localhost data]# cd testdb/
[root@localhost testdb]# ls
a.frm a.ibd db.opt
4.可以看出表使用的是innodb存储引擎
mysql> show create table a\G
*************************** 1. row ***************************
Table: a
Create Table: CREATE TABLE `a` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
5.以myisam存储引擎创建一个测试表tb2
(1)查看mysql存储引擎
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.01 sec)
可以看到InnoDB是默认引擎。
(2)设置InnoDB为默认引擎
在配置文件my.cnf中的[mysqld]下面加入
default-storage-engine=InnoDB
(3)重启mysql服务器
参数解释
“.frm”文件:存放与表相关的元数据(meta)信息,包括表结构的定义信息等。
不论是什么存储引擎(MySQL常用的两个存储引擎是MyISAM和InnoDB),每一个表都会有一个以表名命名的“.frm”文件。
所有的“.frm”文件都存放在所属数据库的文件夹下面。
MyISAM数据库表文件:.MYD文件:表数据文件;.MYI文件:索引文件。
“.MYD”文件:是MyISAM存储引擎专用,存放MyISAM表的数据。每一个MyISAM表都会有一个“.MYD”文件与之对应,同样存放于所属数据库的文件夹下,和“.frm”文件在一起。
“.MYI”文件:也是专属于MyISAM存储引擎的,主要存放MyISAM表的索引相关信息。对于MyISAM存储来说,可以被cache的内容主要就是来源于“.MYI”文件中。每一个MyISAM表对应一个“.MYI”文件,存放于位置和“.frm”以及“.MYD”一样。
InnoDB采用表空间(tablespace)来管理数据,存储表数据和索引。
.ibd文件:单表表空间文件,每个表使用一个表空间文件(file per table),存放用户数据库表数据和索引。InnoDB共享表空间(即InnoDB文件集,ib-file set):ibdata1、ibdata2等,存储InnoDB系统信息和用户数据库表数据和索引,所有表共用。
“.ibd”文件和ibdata文件:这两种文件都是存放Innodb数据的文件,之所以有两种文件来存放Innodb的数据(包括索引),是因为Innodb的数据存储方式能够通过配置来决定是使用共享表空间存放存储数据,还是独享表空间存放存储数据。
独享表空间存储方式使用“.ibd”文件来存放数据,且每个表一个“.ibd”文件,文件存放在和MyISAM数据相同的位置。
如果选用共享存储表空间来存放数据,则会使用ibdata文件来存放,所有表共同使用一个(或者多个,可自行配置)ibdata文件。ibdata文件可以通过innodb_data_home_dir和innodb_data_file_path两个参数共同配置组成。
innodb_data_home_dir:配置数据存放的总目录。
innodb_data_file_path:配置每一个文件的名称。
innodb_data_file_path中可以一次配置多个ibdata文件。文件可以是指定大小,也可以是自动扩展的,但是Innodb限制了仅仅只有最后一个ibdata文件能够配置成自动扩展类型。当我们需要添加新的ibdata文件的时候,只能添加在innodb_data_file_path配置的最后,而且必须重启MySQL才能完成ibdata的添加工作。如果使用独享表空间存储方式的话,就不会有这样的问题。
总结
:共享表空间以及独占表空间都是针对数据的存储方式而言的。
共享表空间:某一个数据库的所有的表数据,索引文件全部放在一个文件中。
独占表空间: 每一个表都将会生成以独立的文件方式来进行存储,每一个表都有一个.frm表描述文件,还有一个.ibd文件。其中这个文件包括了单独一个表的数据内容以及索引内容。
两者之间的优缺点
共享表空间
优点:可以放表空间分成多个文件存放到各个磁盘上。数据和文件放在一起方便管理。
缺点: 所有的数据和索引存放到一个文件中,多个表及索引在表空间中混合存储,这样对于一个表做了大量删除操作后表空间中将会有大量的空隙,特别是对于统计分析,日志系统这类应用最不适合用共享表空间。
独立表空间
优点:
1.每个表都有自已独立的表空间。
2.每个表的数据和索引都会存在自已的表空间中。
3.可以实现单表在不同的数据库中移动。
4.空间可以回收
a)Drop table操作自动回收表空间,如果对于统计分析或是日志表,删除大量数据后可以通过:alter table TableName engine=innodb回缩不用的空间。
b)对于使用独立表空间的表,不管怎么删除,表空间的碎片不会太严重的影响性能,而且还有机会处理。
缺点:
单表增加过大,如超过100个G。
相比较之下,使用独占表空间的效率以及性能会更高一点。
6.查看当前数据库的表空间管理类型
mysql> show variables like '%innodb_file_per%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.00 sec)
ON代表独立表空间管理,OFF代表共享表空间管理;(查看单表的表空间管理方式,需要查看每个表是否有单独的数据文件)
7.Innodb共享表空间配置
(1)修改my.cnf文件
[root@localhost ~]# vim /etc/my.cnf
innodb_file_per_table=0
innodb_data_file_path=ibdata1:100M:autoextend
innodb_data_home_dir=/usr/local/mysql/data
参数解释
innodb_data_home_dir = "/path/" #数据库文件所存放的目录
innodb_log_group_home_dir ="/path/" #日志存放目录
innodb_data_file_path=ibdata1:100M:autoextend #设置一个可扩展大小的尺寸为100MB的数据文件(共享数据文件),名为ibdata1。没有给出文件的位置,所以默认的是在MySQL的数据目录内。
innodb_file_per_table=1|0 #1为使用独占表空间,0为使用共享表空间。
注意
:InnoDB不创建目录,所以在启动服务器之前请确认”所配置的路径目录”的确存在。
(2)重启mysqld服务
[root@localhost ~]# systemctl restart mysqld
Job for mysqld.service failed because the control process exited with error code. See "systemctl status mysqld.service" and "journalctl -xe" for details.
(3)mysqld启动失败,查看错误日志。
# tail -20 /usr/local/mysql/data/mysqld.err
2019-12-29T06:53:44.635783Z 0 [ERROR] InnoDB: The Auto-extending innodb_system
data file '/usr/local/mysql/data/ibdata1' is of a different size 4864 pages
(rounded down to MB) than specified in the .cnf file: initial 6400 pages, max 0
(relevant if non-zero) pages!
注意
:不同版本的mysql报错略有不同,注意看错误日志的内容。从错误日志中显示可以看出在/etc/my.cnf文件中设置6400页而当前ibdata1为4864页,需要计算4864/64=76。修改配置为innodb_data_file_path=ibdata1:76M:autoextend
(4)重启mysqld服务
[root@localhost ~]# systemctl restart mysqld
注意
:计算公式:64pages相当于1M,1page是16KB,如果不清楚默认文件page大小,可以先du -h ibdata1查看,再去设置。
[root@mysql data]# du -h ibdata1
12M ibdata1
这说明mysql5.7.32中ibdata初始化为12M。
mysql> show variables like '%innodb_file_per%';
No connection. Trying to reconnect...
Connection id: 2
Current database: testdb
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF |
+-----------------------+-------+
1 row in set (0.01 sec)
这时新建的表就会使用共享表空间了。
8.Replication相关文件
(1)master.info文件
master.info文件存在于Slave端的数据目录下,里面存放了该Slave的Master端的相关信息,包括Master的主机地址,连接用户,连接密码,连接端口,当前日志位置,已经读取到的日志位置等信息。
(2)relay log和relay log index mysql-relay-bin.xxxxxn
文件用于存放Slave端的I/O线程从Master端所读取到的Binary Log信息,然后由Slave端的SQL线程从该relay log中读取并解析相应的日志信息,转化成Master所执行的SQL语句,然后在Slave端应用。mysql-relay-bin.index文件的功能类似于mysql-bin.index,同样是记录日志的存放位置的绝对路径,只不过他所记录的不是Binary Log,而是Relay Log。
(3)relay-log.info文件
类似于master.info,它存放通过Slave的I/O线程写入到本地的relay log的相关信息。供Slave端的SQL线程以及某些管理操作随时能够获取当前复制的相关信息。
9.其他文件
(1)system config file
系统配置文件一般都是my.cnf,默认存放在”/etc”目录下,my.cnf文件中包含多种参数选项组(group),每一种参数组都通过中括号给定了固定的组名,如“[mysqld]”组中包括了mysqld服务启动时候的初始化参数,“[client]”组中包含着客户端工具程序可以读取的参数。
(2)pid file
pid file是mysqld应用程序在Unix/Linux环境下的一个进程文件,和许多其他Unix/Linux服务端程序一样,存放着自己的进程id。
(3)socket file
socket文件也是在Unix/Linux环境下才有的,用户在Unix/Linux环境下客户端连接可以不通过TCP/IP网络而直接使用Unix Socket来连接MySQL。
mysql有两种连接方式
常用的一般是tcp mysql –h mysql主机ip -uroot -pxxx
mysql -S /path/mysql.sock -u root -pxxx
注意
:采用unix socket连接方式,比用tcp的方式更快,但只适用于mysql和应用同在一台PC上。