mysql sql语句统计查询

环境是mysql8.0

之前调研过mysql audit 插件,均没有发现能适合mysql8.0环境的,除了企业版mysql审计插件,于是想了一个办法,把mysql慢日志时间改为0,这样所有sql都会被记录到慢日志里面,然后在用pt工具解析,过滤,然后写入到数据库。

my.cnf慢日志配置:

slow_query_log_file = /database/mysql/mysql-slow.log
slow_query_log = 1
log_slow_extra=1
long_query_time=0
log_slow_admin_statements=1
log_slow_slave_statements=1

pt-query-digest脚本:

#!/bin/bash
## ==================================================================================
##    让读书成为一种生活方式。就像吃喝拉撒每天必须要干的事,
## 终有一天你的举止、言谈、气质会不一样。 
##                                        —- async 
##
## Created Date: Sunday, 2020-05-16, 3:48:04 pm
## copyright (c):    SZWW Tech. LTD. 
## Engineer:   async 
## Module Name:   
## Revision:   v0.01 
## Description:
##   
## Revision History : 
## Revision     editor         date         Description         
## v0.01        async          2020-05-16   File Created
## ==================================================================================
DIR="$( cd "$( dirname "$0"  )" && pwd  )"
cd $DIR
dt=`date --date='5 min ago' "+%Y-%m-%d %H:%M:%S"`
#配置数据库的连接地址
monitor_db_host="172.18.1.xx"
monitor_db_port=33601
monitor_db_user="xxxxx"
monitor_db_password="xxxxx"
monitor_db_database="xxxx"
dba="xxxxx"
#实例慢日志位置
slowquery_file=/database/mysql/mysql-slow.log
pt_query_digest="/usr/bin/pt-query-digest"
#实例连接信息
hostname="`hostname`" # 和实例配置内容保持一致,用于做筛选

#获取上次分析时间,初始化时请删除last_analysis_time_$hostname文件,可分析全部日志数据
if [ -s ddl_last_analysis_time_$hostname ]; then
    last_analysis_time=`cat ddl_last_analysis_time_$hostname`
else
    last_analysis_time='1000-01-01 00:00:00'
fi

#收集日志
/usr/bin/cat $slowquery_file|grep -vE 'gtid_executed_v3|java' >/database/slow_log/mysql_slow.log && \
$pt_query_digest \
--user=$monitor_db_user --password=$monitor_db_password --port=$monitor_db_port \
--history h=$monitor_db_host,D=$monitor_db_database,t=review_history  \
--no-report --limit=100% --charset=utf8mb4 \
--filter="\$event->{add_column}=length(\$event->{arg}) and \$event->{fingerprint}=~ m/^(create|alter|drop|rename|truncate|comment)/i \
and \$event->{client}=\$event->{ip}" /database/slow_log/mysql_slow.log > /tmp/analysis_slow_query.log
if [ $? -ne 0 ]; then
echo "failed"|/usr/bin/mailx -s "$0 failed on $(hostname) at $(date) " ${dba}
else
echo `date +"%Y-%m-%d %H:%M:%S"`> ddl_last_analysis_time_$hostname
fi

我的日志里面有一些错误格式的日志,所以我把gtid_executed_v3这种过滤掉了,然后过滤出ddl ~ m/^(create|alter|drop|rename|truncate|comment)/i ,过滤dml为 ~ m/^(update|insert|delete)/i ,我主要过滤我关注的几类,然后写入表 review_history 

review_history建表语句:

CREATE TABLE review_history (
  id int(11) NOT NULL AUTO_INCREMENT,
  hostname_max varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs DEFAULT NULL,
  client_max varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs DEFAULT NULL,
  user_max varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs DEFAULT NULL,
  db_max varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs DEFAULT NULL,
  checksum char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs DEFAULT NULL,
  sample longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs,
  ts_min timestamp NULL DEFAULT NULL,
  ts_max timestamp NULL DEFAULT NULL,
  ts_cnt float DEFAULT NULL,
  Query_time_sum float DEFAULT NULL,
  Query_time_min float DEFAULT NULL,
  Query_time_max float DEFAULT NULL,
  Query_time_pct_95 float DEFAULT NULL,
  Query_time_stddev float DEFAULT NULL,
  Query_time_median float DEFAULT NULL,
  Lock_time_sum float DEFAULT NULL,
  Lock_time_min float DEFAULT NULL,
  Lock_time_max float DEFAULT NULL,
  Lock_time_pct_95 float DEFAULT NULL,
  Lock_time_stddev float DEFAULT NULL,
  Lock_time_median float DEFAULT NULL,
  Rows_sent_sum float DEFAULT NULL,
  Rows_sent_min float DEFAULT NULL,
  Rows_sent_max float DEFAULT NULL,
  Rows_sent_pct_95 float DEFAULT NULL,
  Rows_sent_stddev float DEFAULT NULL,
  Rows_sent_median float DEFAULT NULL,
  Rows_examined_sum float DEFAULT NULL,
  Rows_examined_min float DEFAULT NULL,
  Rows_examined_max float DEFAULT NULL,
  Rows_examined_pct_95 float DEFAULT NULL,
  Rows_examined_stddev float DEFAULT NULL,
  Rows_examined_median float DEFAULT NULL,
  Rows_affected_sum float DEFAULT NULL,
  Rows_affected_min float DEFAULT NULL,
  Rows_affected_max float DEFAULT NULL,
  Rows_affected_pct_95 float DEFAULT NULL,
  Rows_affected_stddev float DEFAULT NULL,
  Rows_affected_median float DEFAULT NULL,
  Rows_read_sum float DEFAULT NULL,
  Rows_read_min float DEFAULT NULL,
  Rows_read_max float DEFAULT NULL,
  Rows_read_pct_95 float DEFAULT NULL,
  Rows_read_stddev float DEFAULT NULL,
  Rows_read_median float DEFAULT NULL,
  Merge_passes_sum float DEFAULT NULL,
  Merge_passes_min float DEFAULT NULL,
  Merge_passes_max float DEFAULT NULL,
  Merge_passes_pct_95 float DEFAULT NULL,
  Merge_passes_stddev float DEFAULT NULL,
  Merge_passes_median float DEFAULT NULL,
  InnoDB_IO_r_ops_min float DEFAULT NULL,
  InnoDB_IO_r_ops_max float DEFAULT NULL,
  InnoDB_IO_r_ops_pct_95 float DEFAULT NULL,
  InnoDB_IO_r_ops_stddev float DEFAULT NULL,
  InnoDB_IO_r_ops_median float DEFAULT NULL,
  InnoDB_IO_r_bytes_min float DEFAULT NULL,
  InnoDB_IO_r_bytes_max float DEFAULT NULL,
  InnoDB_IO_r_bytes_pct_95 float DEFAULT NULL,
  InnoDB_IO_r_bytes_stddev float DEFAULT NULL,
  InnoDB_IO_r_bytes_median float DEFAULT NULL,
  InnoDB_IO_r_wait_min float DEFAULT NULL,
  InnoDB_IO_r_wait_max float DEFAULT NULL,
  InnoDB_IO_r_wait_pct_95 float DEFAULT NULL,
  InnoDB_IO_r_wait_stddev float DEFAULT NULL,
  InnoDB_IO_r_wait_median float DEFAULT NULL,
  InnoDB_rec_lock_wait_min float DEFAULT NULL,
  InnoDB_rec_lock_wait_max float DEFAULT NULL,
  InnoDB_rec_lock_wait_pct_95 float DEFAULT NULL,
  InnoDB_rec_lock_wait_stddev float DEFAULT NULL,
  InnoDB_rec_lock_wait_median float DEFAULT NULL,
  InnoDB_queue_wait_min float DEFAULT NULL,
  InnoDB_queue_wait_max float DEFAULT NULL,
  InnoDB_queue_wait_pct_95 float DEFAULT NULL,
  InnoDB_queue_wait_stddev float DEFAULT NULL,
  InnoDB_queue_wait_median float DEFAULT NULL,
  InnoDB_pages_distinct_min float DEFAULT NULL,
  InnoDB_pages_distinct_max float DEFAULT NULL,
  InnoDB_pages_distinct_pct_95 float DEFAULT NULL,
  InnoDB_pages_distinct_stddev float DEFAULT NULL,
  InnoDB_pages_distinct_median float DEFAULT NULL,
  QC_Hit_cnt float DEFAULT NULL,
  QC_Hit_sum float DEFAULT NULL,
  Full_scan_cnt float DEFAULT NULL,
  Full_scan_sum float DEFAULT NULL,
  Full_join_cnt float DEFAULT NULL,
  Full_join_sum float DEFAULT NULL,
  Tmp_table_cnt float DEFAULT NULL,
  Tmp_table_sum float DEFAULT NULL,
  Tmp_table_on_disk_cnt float DEFAULT NULL,
  Tmp_table_on_disk_sum float DEFAULT NULL,
  Filesort_cnt float DEFAULT NULL,
  Filesort_sum float DEFAULT NULL,
  Filesort_on_disk_cnt float DEFAULT NULL,
  Filesort_on_disk_sum float DEFAULT NULL,
  Bytes_sum float DEFAULT NULL,
  Bytes_min float DEFAULT NULL,
  Bytes_max float DEFAULT NULL,
  Bytes_pct_95 float DEFAULT NULL,
  Bytes_stddev float DEFAULT NULL,
  Bytes_median float DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY checksum (checksum,ts_min,ts_max),
  KEY idx_hostname_max_ts_min (hostname_max,ts_min)
) ENGINE=InnoDB AUTO_INCREMENT=797 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_as_cs ROW_FORMAT=COMPRESSED

参考官方链接https://www.percona.com/doc/percona-toolkit/3.0/pt-query-digest.html

然后加入crontab,每个几分钟执行一次,后来发现这样会漏记录一些sql,频繁去解析slow_log对操作系统io也有一定消耗,思考以后,改成了每隔6小时全量执行一次,这样就会有一点延时,不过这个主要用于审计sql,延时也能接受,如果要实时,在想想办法。不增量以后,没再发现漏记sql。

主要就是pt的filter参数:

 --filter="\$event->{add_column}=length(\$event->{arg}) and \$event->{hostname}=\"$hostname\" and \$event->{client}=\$event->{ip}" \ 

一开始是这样写的,记录的太多,查表筛选的时候慢,于是只过滤了自己需要的类型ddl与dml:

--filter="\$event->{add_column}=length(\$event->{arg}) and \$event->{fingerprint}=~ m/^(create|alter|drop|rename|truncate|comment|delete|insert|update)/i \
and \$event->{client}=\$event->{ip}"

然后修改下脚本就实现了mysql的sql审计,然后再配合init-connect,可以实现比较精准快速的排查问题。

猜你喜欢

转载自www.cnblogs.com/5sdba-notes/p/12905054.html
今日推荐