Mysql慢查询日志文件转Excel的方法

 更新时间:2024年10月31日 14:08:21   作者:佳楠  
面对公司生产环境中慢SQL问题的排查工作,由于日志文件格式混乱,相关资料无法提供便捷的格式化处理工具,故而自主编写一套Java读取慢SQL日志转为Excel的小工具,该工具可以有效提升排查工作的效率,方便快捷地解决问题

最近公司生产环境需要排查慢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());
        }
    }

到此这篇关于Mysql慢查询日志文件转Excel的方法的文章就介绍到这了,更多相关Mysql慢查询日志文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mysql配置my.ini文件的简单成功版本

    Mysql配置my.ini文件的简单成功版本

    my.ini是MySQL数据库中使用的配置文件,修改这个文件可以达到更新配置的目的,下面这篇文章主要给大家介绍了关于Mysql配置my.ini文件的简单成功版本,需要的朋友可以参考下
    2023-04-04
  • MySQL的指定范围随机数函数rand()的使用技巧

    MySQL的指定范围随机数函数rand()的使用技巧

    这篇文章主要介绍了MySQL的指定范围随机数函数rand()的使用技巧,需要的朋友可以参考下
    2016-09-09
  • MYSQL中常用的强制性操作(例如强制索引)

    MYSQL中常用的强制性操作(例如强制索引)

    对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法。同样,在mysql里,也有类似的hint功能。
    2014-05-05
  • Mysql如何查看表及字段信息

    Mysql如何查看表及字段信息

    这篇文章主要介绍了Mysql如何查看表及字段信息,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • MySQL双主搭建+keepalived高可用的实现

    MySQL双主搭建+keepalived高可用的实现

    本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04
  • 关于MySQL数据库死锁的案例和解决方案

    关于MySQL数据库死锁的案例和解决方案

    MySQL Update语句防止死锁是指在修改MySQL数据库的数据时,为避免多个进程同时修改同一数据行而造成死锁的情况,引入了一些机制来防止死锁的产生,本文介绍了一个 MySQL 数据库死锁的案例和解决方案,需要的朋友可以参考下
    2023-09-09
  • Mysql通过存储过程分割字符串为数组

    Mysql通过存储过程分割字符串为数组

    今天小编就为大家分享一篇关于Mysql通过存储过程分割字符串为数组,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • 解决Mysql主从错误:could not find first log file name in binary

    解决Mysql主从错误:could not find first log&nbs

    这篇文章主要介绍了解决Mysql主从错误:could not find first log file name in binary问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • MySQL 8.0.20 安装教程图文详解(windows 64位)

    MySQL 8.0.20 安装教程图文详解(windows 64位)

    这篇文章主要介绍了MySQL 8.0.20安装教程(windows 64位),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有,需要的朋友可以参考下
    2020-05-05
  • Windows版mysql 8.0.28 安装配置方法图文教程

    Windows版mysql 8.0.28 安装配置方法图文教程

    这篇文章主要为大家详细介绍了Windows版mysql 8.0.28 安装配置方法图文教程,文中安装步骤介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06

最新评论