Mysql slow 分析脚本

@Ta 2022-08-31发布,2022-08-31修改 7384点击

提取mysql慢sql的shell脚本,适合crontab使用

源码:

#!/bin/bash
#
# Mysql slow 分析脚本
# Operating System: CentOS Linux 7 (Core)
# Date: 20220830
#


Version="0.1"

init()
{
    #环境变量
    source /etc/profile
    export PATH=${PATH}:/usr/sbin
    
    #脚本所在目录
    SHELL_FOLDER=$(dirname $(readlink -f "$0"))

    #慢sql文件
    slowLogFile="/hkdata/mysql/slow.log"

    #是否告警
    IS_alert="1"

    #邮箱地址
    Mail=""
    
    #本机IP地址
    Ip_Addr="`ip a s | grep global | grep -v "192.168" | awk '{print $2}' | head -n 1 | cut -d "/" -f 1`"
    
    #慢SQL秒,大于等于
    sec="5"
    
}

main()
{
    #判断日志文件是否存在
    if ! test -f $slowLogFile; then
        echo "$slowLogFile 日志文件不存在!"
        exit 0
    fi
    
    
    #获取文本内部开始时间(第一次运行时默认从上次记录文本里取,如果没有默认查找slow最后行的)
    if test -f startDATE.txt; then
        startDATE="$(cat ${SHELL_FOLDER}/startDATE.txt)"        #开始时间(当分隔符),如果不存在也没事
    else
        :
    fi

    endDATE="$(tail -n 1024 ${slowLogFile} | grep "# Time:" | tail -n1 | cut -d "+" -f 1)"      #结束时间(当分隔符)
    if test "$endDATE" = ""; then                                                               #如果为空增大查找范围
        endDATE="$(tail -n 4096 ${slowLogFile} | grep "# Time:" | tail -n1 | cut -d "+" -f 1)"
    fi

    if test "$endDATE" != ""; then                                                              #下一次运行充当开始时间的分隔符
        echo $endDATE > startDATE.txt
    fi


    #startDATE="Time: 2022-08-30T10:22:35.455603"       #测试
    #endDATE="# Time: 2022-08-30T10:26:15.097185"       #测试

    if test "$startDATE" != "$endDATE"; then
        awk '/'"${startDATE}"'/,/'"${endDATE}"'/{if(i>=1)print x; x=$0; i++}' ${slowLogFile} > ${SHELL_FOLDER}/newSlow.txt      #正则匹配,输出 "# Time: 2022-08-19T16:54:45.849179"行 至 "# Time: 2022-08-19T16:54:45.849179"行 到newSlow.txt文件
        echo $endDATE >> ${SHELL_FOLDER}/newSlow.txt

        cat ${SHELL_FOLDER}/newSlow.txt | while read line; do       #判断输出文件的否合格(可与忽略)
        
            result=$(echo $line | grep "# Time: ")       
            if [[ "$result" != "" ]]; then
                echo $line >> $SHELL_FOLDER/temp.txt        
                
            else
                echo $line >> $SHELL_FOLDER/temp.txt

            fi
        done
    else
        echo "文本没有变化!没有新日志产生"
        exit 0                      #开始时间等于结束时间时,slow.log文件没有更新。退出
    fi

}

Split_text()
{

    TArray=(`awk '/Time:/,/Time:/{print}' $SHELL_FOLDER/temp.txt  | cut -d "+" -f 1 | awk '{print $3}'`)             #从$SHELL_FOLDER/temp.txt 文件中找"时间",并存储在数组中当分割符。(目的是分割每一个慢sql)
    echo ${TArray[0]}
    
    for((i=0; i<${#TArray[@]}; i++))            #遍历数组
    do
        echo "$i"
        let t=i                             #i作为数组下标
        let t=t+1                           #t作为下一个数组下标
        awk '/'"${TArray[i]}"'/,/'"${TArray[t]}"'/{if(i>=1)print x; x=$0; i++}' ${slowLogFile} > ${SHELL_FOLDER}/3.txt   #分割好的每个sql信息存储在3.txt
        
        Time="`grep Query_time 3.txt | awk '{print $3}' | cut -d "." -f 1`"                                      #查找3.txt的Query_time值
        echo "慢SQL时间: ${Time}"
        
        if test "${Time}" != ""; then
            
            if [ "${Time}" -ge "${sec}" ]; then     #大于等于5秒的sql
                cat 3.txt >> sql5.log               #追加到5秒集合中
            fi
            
        fi

    done
    
    #删除不需要的文件
    rm ${SHELL_FOLDER}/temp.txt
    rm ${SHELL_FOLDER}/newSlow.txt
    
}

send_mail()
{
    if test "$IS_alert" = "1"; then     #是否告警
    
        back_size5=$(stat -c "%s" $SHELL_FOLDER/sql5.log)
        if [[ $back_size5 > 1 ]];then
            
            
            echo "出现慢sql(超过${sec}s),附件为sql语句。服务器IP:${Ip_Addr}" | \
                mail -s "慢sql语句(超过${sec}s),服务器IP:${Ip_Addr}" -a ${SHELL_FOLDER}/sql5.log ${Mail}
                
            echo "" > ${SHELL_FOLDER}/sql5.log              #发送完邮件后清空,等下次运行追加
        fi
        
    fi

}

help_()
{
    cat <<EOF
    
    Mysql slow 分析脚本 Version: ${Version}

Usage:
    ${0} [-xfmsah]
    
Options:
        -x  : Print Debug .
        -f  : MySQL slow SQL file .
        -m  : Mailing List .
        -s  : Slow SQL seconds .
        -a  : Alarm or not .
        -h  : Print Help .

EOF
    exit 0
}


init
while getopts :xf:m:s:a:h? arg; do
    case ${arg} in
        x)
            debug=x;
            ;;
        f)
            slowLogFile="$OPTARG";
            ;;
        m)
            Mail="$OPTARG";
            ;;
        s)
            sec="$OPTARG";
            ;;
        a)
            IS_alert="$OPTARG";
            ;;
        h|?)
            help_
            ;;
    esac

done
shift $((OPTIND-1));        #参数移位
test "${debug}" = "x" && set -x;
main
Split_text
send_mail


回复列表(2|隐藏机器人聊天)
添加新回复
回复需要登录