首页 > 数据库 >Mysql慢日志转Excel

Mysql慢日志转Excel

时间:2024-10-31 13:47:06浏览次数:6  
标签:String slowQueries Excel sqlQuery Mysql slowQuery new 日志 setCellValue

最近公司生产环境需要排查慢SQL,导出日志txt文件后排查混乱,查找相关资料后并没有找到方便快捷的格式化处理工具,于是自己编写了一套Java读取慢SQL日志转为Excel小工具。

@Data
public class SlowQuery {
    private double queryTime;
    private double lockTime;
    private String sqlQuery;
    private String tableName;
    private Date executionDate;

}
public class MySQLSlowQueryLogParser {

    //  正则表达式匹配 慢日志内容格式抓取
    private static final Pattern QUERY_TIME_PATTERN = Pattern.compile("# Query_time: (\\d+\\.\\d+)");
    private static final Pattern LOCK_TIME_PATTERN = Pattern.compile("  Lock_time: (\\d+\\.\\d+)");
    private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("SET timestamp=(\\d+);");

    public static void main(String[] args) {
        MySQLSlowQueryLogParser parser = new MySQLSlowQueryLogParser();

        //  慢查询日志存放路径
        String filePath = "D:\\日常\\2.OA\\OASERVERLANDB-slow.log";
        //  导出Excel路径
        String excelPath = "D:\\日常\\2.OA\\slow_queries.xlsx";
        //  读取慢查询日志
        List<SlowQuery> slowQueries = parser.readSlowQueryLog(filePath);
        //  写入本地Excel中
        parser.writeQueriesToExcel(slowQueries, excelPath);
    }

    /**
     * 读取慢查询日志 返回List对象
     * @param filePath 慢查询日志文件路径
     * @return List<SlowQuery> 解析结果
     * */
    public List<SlowQuery> readSlowQueryLog(String filePath) {
        List<SlowQuery> slowQueries = new ArrayList<>();

        //  转流
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            StringBuilder queryBuilder = new StringBuilder();
            //  设定默认值
            double queryTime = 0;
            double lockTime = 0;
            boolean isSlowQuery = false;
            long timestamp = 0; // 用于存储时间戳

            while ((line = br.readLine()) != null) {
                if (line.startsWith("# Query_time")) {
                    // 如果前一个查询存在,添加到列表
                    if (isSlowQuery) {
                        addSlowQuery(slowQueries, queryTime, lockTime, queryBuilder.toString().trim(), timestamp);
                    }

                    // 解析查询时间和锁定时间
                    Matcher queryTimeMatcher = QUERY_TIME_PATTERN.matcher(line);
                    if (queryTimeMatcher.find()) {
                        queryTime = Double.parseDouble(queryTimeMatcher.group(1));
                    }

                    Matcher lockTimeMatcher = LOCK_TIME_PATTERN.matcher(line);
                    if (lockTimeMatcher.find()) {
                        lockTime = Double.parseDouble(lockTimeMatcher.group(1));
                    }

                    // 开始新的慢查询
                    isSlowQuery = true;
                    // 清空缓存
                    queryBuilder.setLength(0);
                } else if (line.startsWith("SET timestamp")) {
                    // 提取时间戳
                    Matcher timestampMatcher = TIMESTAMP_PATTERN.matcher(line);
                    if (timestampMatcher.find()) {
                        timestamp = Long.parseLong(timestampMatcher.group(1)); // 获取时间戳
                    }
                } else if (line.startsWith("#") || line.trim().isEmpty()) {
                    // 忽略注释行和空行
                    continue;
                } else {
                    // 记录当前慢查询的内容
                    if (isSlowQuery) {
                        queryBuilder.append(line).append("\n");
                    }
                }
            }

            // 处理最后一个慢查询
            if (queryBuilder.length() > 0) {
                addSlowQuery(slowQueries, queryTime, lockTime, queryBuilder.toString().trim(), timestamp);
            }
        } catch (IOException e) {
            System.out.printf(e.toString());
        }
        return slowQueries;
    }

    /**
     * 添加慢查询对象
     * @param slowQueries List<SlowQuery> 慢查询对象集合
     * @param queryTime 查询时间
     * @param lockTime 锁定时间
     * @param sqlQuery Sql执行时间
     * @param timestamp 时间戳
     * */
    private void addSlowQuery(List<SlowQuery> slowQueries, double queryTime, double lockTime, String sqlQuery, long timestamp) {
        SlowQuery slowQuery = new SlowQuery();
        slowQuery.setQueryTime(queryTime);
        slowQuery.setLockTime(lockTime);
        slowQuery.setSqlQuery(sqlQuery);
        // 提取表名
        slowQuery.setTableName(extractTableName(sqlQuery));
        // 设置执行日期
        slowQuery.setExecutionDate(new Date(timestamp * 1000));
        slowQueries.add(slowQuery);
    }


    /**
     * 通过Sql语句中 提取出表名
     * @param sqlQuery 执行的Sql语句
     * @return 表名
     * */
    private String extractTableName(String sqlQuery) {
        Pattern pattern = Pattern.compile("FROM\\s+([\\w.]+)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(sqlQuery);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return "";
    }

    /**
     * 通过处理后的集合生成到指定路径
     * @param slowQueries 数据集合
     * @param filePath 导出的Excel路径
     * */
    public void writeQueriesToExcel(List<SlowQuery> slowQueries, String filePath) {
        final int MAX_CELL_LENGTH = 32767;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 日期格式化

        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Slow Queries");

            // 创建标题行
            Row headerRow = sheet.createRow(0);
            headerRow.createCell(0).setCellValue("Query Time (s)");
            headerRow.createCell(1).setCellValue("Lock Time (s)");
            headerRow.createCell(2).setCellValue("SQL Query");
            headerRow.createCell(3).setCellValue("Table Name");
            headerRow.createCell(4).setCellValue("Execution Date");

            // 填充数据行
            int rowNum = 1;
            for (SlowQuery slowQuery : slowQueries) {
                Row row = sheet.createRow(rowNum++);
                row.createCell(0).setCellValue(slowQuery.getQueryTime());
                row.createCell(1).setCellValue(slowQuery.getLockTime()); // 确保这里写入的是原始 double 值

                String sqlQuery = slowQuery.getSqlQuery();
                if (sqlQuery.length() > MAX_CELL_LENGTH) {
                    sqlQuery = sqlQuery.substring(0, MAX_CELL_LENGTH);
                }
                row.createCell(2).setCellValue(sqlQuery);
                row.createCell(3).setCellValue(slowQuery.getTableName());
                row.createCell(4).setCellValue(dateFormat.format(slowQuery.getExecutionDate()));
            }

            // 写入到文件
            try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
                workbook.write(fileOut);
            }
        } catch (IOException e) {
            System.out.printf(e.toString());
        }
    }

标签:String,slowQueries,Excel,sqlQuery,Mysql,slowQuery,new,日志,setCellValue
From: https://www.cnblogs.com/shangjianan/p/18517599

相关文章

  • MySQL从节点异常宕机重启后遇到主键冲突
    一台虚机在迁移过程中遇到点问题,然后运维做了重启的操作。重启后,发现该虚机中的mysql从库与主库的同步失败了。登录后查看,发现sqlthread停止运行了:mysql>showslavestatus\G***************************1.row***************************Slave_IO_St......
  • 小白手把手教学用spring框架实现mybatis和mysql以及工作原理
    Maven_Mybatis_Mysql什么是MybatisMyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和JavaPOJO(PlainOldJavaObj......
  • efk日志收集系统配置模板
    一、被收集日志端服务器的配置:1. docker-compose.yaml的配置:#version:'2'services:filebeat:image:docker.elastic.co/beats/filebeat:8.10.2container_name:filebeatnetworks:-loggingvolumes:-./filebeat/filebeat.yml:/usr/share/filebe......
  • MySQL的主从切换在什么情况下使用
    主从切换一般在如下情况下才进行:1、例行的主库重启,主库运行一段时间后需要将主库进行重启扫盘,降低主库死机的风险;2、主库异常情况下切到从库。3、分机房网络调整涉及到主库的情况。一、MySQL的主从切换在什么情况下使用主从切换一般在如下情况下才进行:1、例行的主库重启,主库......
  • 遇到慢查询怎么办?一文解读MySQL 8.0查询分析工具
    本文分享自华为云社区《【华为云MySQL技术专栏】MySQL8.0EXPLAINANALYZE工具介绍》,作者:GaussDB数据库。1.EXPLAINANALYZE可以解决什么问题MySQL8.0.18版本开始支持查询分析工具EXPLAINANALYZE,该工具不仅会实际执行SQL语句,还会展示SQL语句详细的执行信息,包含执行算子(It......
  • 记录NPOI导出Excel并使用不同颜色标注特定条件相同的行
    一、环境概述开发工具:VisualStudio2022.Net环境:.NetCore6.0相关依赖:NPOI二、基本概述需求要实现导出的数据里如果连续行满足某个条件就用颜色标记,但是标记的区间要用不同颜色区分开,用了双指针,但是是记录了起始位置和偏移量,封装比较屎,这里主要记录一下思想。三、代码实......
  • 织梦取消MySQL错误日志生成文件功能防止暴露后台和管理员
    问题描述织梦程序在MySQL错误时会生成 mysql_error_trace.inc 文件,记录错误信息,可能导致后台目录和管理员账号信息泄露。解决方法编辑 dedesql.class.php 文件打开 /include/dedesql.class.php 文件。删除错误日志生成代码找到以下代码并删除://保存MySql错......
  • MySQL max_allowed_packet参数设置
    MySQL根据配置文件会限制Server接受的数据包大小。有时候大的插入和更新会受max_allowed_packet参数限制,导致写入或者更新失败。(比方说导入数据库,数据表)查看目前配置:代码如下:mysql>showVARIABLESlike'%max_allowed_packet%';+--------------------------+--------......
  • mysql 一次插入多少数据性能最佳
    mysql一次插入多少条是最佳性能我们经常会浏览,分享,点赞,都会产生数据,这些数可能会被存储到不同的地方,其中最常见的存储载体就是--数据库。根据场景和数据特性,可以有关系型数据库mysql,也有非关系数据库,例如:Redis,比如说:当你在网站点赞的时候,为了快速响应,可能是一个基于内存的......
  • Python 自动化运维:日志与监控的深度探索
    Python自动化运维:日志与监控的深度探索目录......