Python实现Java mybatis-plus 产生的SQL自动化测试SQL速度和判断SQL是否走索引
Python实现Java mybatis-plus 产生的SQL自动化测试SQL速度和判断SQL是否走索引
文件目录如下
│ sql_speed_test.py
│
├─input
│ data-report_in_visit_20240704.log
│ resource_in_sso_20240704.log
│
└─outputdata-report_in_visit_20240704.csvresource_in_sso_20240704.csv
目前每次做实验都要将Java中的SQL做性能测试,否则就没法通过考核,属实难崩。
sql_speed_test.py是我用python写的程序,将从Java mybatis-plus控制台产生的日志复制到data-report_in_visit_20240704.log和resource_in_sso_20240704.log文件中,运行程序之后output文件夹会自动输出csv文件,下面为csv文件夹详情。
data-report_in_visit_20240704.log文件
-- 301 -- [2024-07-04 14:22:55.055] [org.apache.ibatis.logging.jdbc.BaseJdbcLogger] [http-nio-9006-exec-2] [143] [DEBUG] [traceId:] ==>
SELECT resource_id AS resource_id, resource_type AS resource_type, sum(IFNULL(internal_pv, pv)) AS internal_pv, sum(IFNULL(google_pv, pv)) AS google_pv, sum(IFNULL(other_pv, pv)) AS other_pv, sum(IFNULL(pv, 0)) AS pv FROM t_bw_article_daily_statistic where resource_type = 9 GROUP BY resource_id, resource_type order by resource_id, resource_type
-- 302 -- [2024-07-04 14:22:55.055] [org.apache.ibatis.logging.jdbc.BaseJdbcLogger] [http-nio-9006-exec-2] [143] [DEBUG] [traceId:] ==>
SELECT resource_id AS resource_id, resource_type AS resource_type, sum(IFNULL(internal_pv, pv)) AS internal_pv, sum(IFNULL(google_pv, pv)) AS google_pv, sum(IFNULL(other_pv, pv)) AS other_pv, sum(IFNULL(pv, 0)) AS pv FROM t_bw_article_daily_statistic_202406 where resource_type = 9 GROUP BY resource_id, resource_type order by resource_id, resource_type
data-report_in_visit_20240704.csv文件
| 序号 | SQL功能描述 | SQL | 预估业务数据量 | 实际测试数据量 | 执行时间 | 执行结果 | 索引是否生效 | 所属项目 | 所在库 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | SELECT resource_id AS resource_id, resource_type AS resource_type, sum(IFNULL(internal_pv, pv)) AS internal_pv, sum(IFNULL(google_pv, pv)) AS google_pv, sum(IFNULL(other_pv, pv)) AS other_pv, sum(IFNULL(pv, 0)) AS pv FROM t_bw_article_daily_statistic where resource_type = 9 GROUP BY resource_id, resource_type order by resource_id, resource_type | t_bw_article_daily_statistic | t_bw_article_daily_statistic:5741行 | 0.419603 秒 | 462 | 是 | data-report | visit | |
| 2 | SELECT resource_id AS resource_id, resource_type AS resource_type, sum(IFNULL(internal_pv, pv)) AS internal_pv, sum(IFNULL(google_pv, pv)) AS google_pv, sum(IFNULL(other_pv, pv)) AS other_pv, sum(IFNULL(pv, 0)) AS pv FROM t_bw_article_daily_statistic_202406 where resource_type = 9 GROUP BY resource_id, resource_type order by resource_id, resource_type | t_bw_article_daily_statistic_202406 | t_bw_article_daily_statistic_202406:296358行 | 0.291532 秒 | 2691 | 是 | data-report | visit |
sql_speed_test.py文件
import os
import csv
import re
from pymysql import *
import time"""
开发一个用于SQL性能测试的工具,避免一直做重复工作
将Java中的每一条SQL采用mybatis-plus-plugin插件抓出来转存至log文件中
抓住每条SQL做测试
"""def extract_query_sql_table_names(sql):# 正则表达式模式pattern = re.compile(r"\b(?:FROM|JOIN|INTO|UPDATE|TABLE|INTO)\s+([`\"\[\]]?[a-zA-Z_][\w$]*[`\"\[\]]?)",re.IGNORECASE)# 查找所有匹配的表名matches = pattern.findall(sql)# 去掉引号和方括号tables = [re.sub(r'[`"\[\]]', '', match) for match in matches]filter_tables = []for table in tables:if "t_bw" in table:filter_tables.append(table)return filter_tablesdef check_index_usage(connection, sql):if not sql.startswith("select") and not sql.startswith("SELECT"):return Falsetry:with connection.cursor() as cursor:# 使用 EXPLAIN 来获取查询计划explain_sql = f"EXPLAIN {sql}"cursor.execute(explain_sql)explain_result = cursor.fetchall()# 打印 EXPLAIN 结果print("EXPLAIN 结果:")for row in explain_result:print(row)# 检查每行是否使用了索引for row in explain_result:if row[5] is not None:print(f"SQL 使用了索引: {row[5]}")return Trueprint("SQL 未使用索引")return Falsefinally:pass# connection.close()def count_rows(connection, table_name):try:with connection.cursor() as cursor:# 构建 SQL 语句sql = f"SELECT COUNT(*) FROM {table_name}"# 执行 SQL 语句cursor.execute(sql)# 获取结果result = cursor.fetchone()# 返回结果return result[0]except Exception as e:print(e)finally:# connection.close()passclass SqlSpeedTest:def __init__(self):self.input_dir = "./input"self.output_dir = "./output"self.databases = {"sso": {"ip": "xxxxxx","database": "sso","username": "xxxx","password": "xxxx"}}def get_all_input_files(self):files = os.listdir(r'./input')# file_paths = []# for file in files:# file_paths.append(self.input_dir + "/" + file)return filesdef handle_sql_log(self, project, database, lines):sql_lines = []row_count = 1database_info = self.databases.get(database)conn = connect(host=database_info.get("ip"),port=3306,user=database_info.get("username"),password=database_info.get("password"),database=database_info.get("database"),charset='utf8mb4')for index, line in enumerate(lines):if line.startswith("--"):continuecurrent_sql = line.replace("\n", "")execute_info = self.execute_sql_and_get_execute_time(conn, database, current_sql)tables = extract_query_sql_table_names(current_sql)real_rows = ""for table in tables:total_rows = count_rows(conn, table)real_rows += f"{table}:{total_rows}行 "sql_line = {"row_count": row_count,"sql_description": "","sql": current_sql,"expect_rows": ",".join(tables),"real_rows": real_rows,"execute_time": execute_info["execute_time"],"execute_rows": execute_info["execute_rows"],"index_has_work": execute_info["index_has_work"],"project": project,"project": project,"database": database}sql_lines.append(sql_line)row_count += 1conn.close()return sql_linesdef execute_sql_and_get_execute_time(self, conn, database, sql):print(f"==================> {database}库正在执行SQL: {sql}")# 记录开始时间try:cs = conn.cursor() # 获取光标start_time = time.time()cs.execute(sql)rows = cs.fetchall()# 记录结束时间end_time = time.time()# 计算执行时间execution_time = end_time - start_timeconn.commit()print(f"======>{database}库共花费{execution_time:.6f}秒执行完毕,{sql}")except Exception as e:print(e)return {"execute_rows": "", "execute_time": "", "index_has_work": ""}index_has_work = check_index_usage(conn, sql)return {"execute_rows": len(rows), "execute_time": f"{execution_time:.6f} 秒","index_has_work": "是" if index_has_work else "否"}def handle_log_file(self, filename):with open(self.input_dir + "/" + filename, "r", encoding="utf-8") as file:lines = file.readlines()pre_filename = filename.split(".")[0]with open(self.output_dir + "/" + pre_filename + ".csv", "w", newline='', encoding='utf-8-sig') as f:writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL)csv_title = ["序号", "SQL功能描述", "SQL", "预估业务数据量", "实际测试数据量", "执行时间", "执行结果","索引是否生效", "所属项目", "所在库"]writer.writerow(csv_title)info = pre_filename.split("_in_")project_name = info[0]database_name = info[1].split("_")[0]sql_lines = self.handle_sql_log(project_name, database_name, lines)for sql_line in sql_lines:write_line = [sql_line["row_count"],sql_line["sql_description"],sql_line["sql"],sql_line["expect_rows"],sql_line["real_rows"],sql_line["execute_time"],sql_line["execute_rows"],sql_line["index_has_work"],sql_line["project"],sql_line["database"]]writer.writerow(write_line)def do_work(self):files = self.get_all_input_files()for file in files:self.handle_log_file(file)if __name__ == '__main__':sql_speed_test = SqlSpeedTest()sql_speed_test.do_work()
写在最后
编程精选网(www.codehuber.com),程序员的终身学习网站已上线!
如果这篇【文章】有帮助到你,希望可以给【JavaGPT】点个赞👍,创作不易,如果有对【后端技术】、【前端领域】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【JavaGPT】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💝💝💝!
相关文章:
Python实现Java mybatis-plus 产生的SQL自动化测试SQL速度和判断SQL是否走索引
Python实现Java mybatis-plus 产生的SQL自动化测试SQL速度和判断SQL是否走索引 文件目录如下 │ sql_speed_test.py │ ├─input │ data-report_in_visit_20240704.log │ resource_in_sso_20240704.log │ └─outputdata-report_in_visit_20240704.cs…...
UDP的报文结构及其注意事项
1. 概述 UDP(User Datagram Protocol)是一种无连接的传输层协议,它提供了一种简单的数据传输服务,不保证数据的可靠传输。在网络通信中,UDP通常用于一些对实时性要求较高、数据量较小、传输延迟较低的应用,…...
MySQL深度分页问题深度解析与解决方案
文章目录 引言深度分页问题的原因解决方案方案一:使用主键索引优化方案二:使用子查询优化方案三:使用INNER JOIN优化方案四:使用搜索引擎 最佳实践结论 引言 在处理包含数百万条记录的大型数据表时,使用MySQL的LIMIT进…...
C#类型基础Part1-值类型与引用类型
C#类型基础Part1-值类型与引用类型 参考资料前言值类型引用类型装箱和拆箱 参考资料 《.NET之美–.NET关键技术深入与解析》 前言 C#中的类型一共分为两类,一类是值类型(Value Type),一类是引用类型(Reference Type)…...
被上市公司预判的EPS增速分析
EPS增速对二级市场投资和估值有着很显著的影响,上市公司显然也知道这一点。对于想要做市值管理的上市公司来说,调节EPS增速比调节EPS更加有效。因此《穿透财报:读懂财报中的逻辑与陷阱》中的作者在第四章正式提出了二级市场财务分析中的额动态…...
快速入门了解Ajax
博客主页:音符犹如代码系列专栏:JavaWeb关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Ajax的初识 意义:AJAX(Asynchronous JavaScript and…...
FPGA开发——呼吸灯的设计
一、原理 呼吸灯的原理主要基于PWM(脉冲宽度调制)技术,通过控制LED灯的占空比来实现亮度的逐渐变化。这种技术通过调整PWM信号的占空比,即高电平在一个周期内所占的比例,来控制LED灯的亮度。当占空比从0%逐渐变化到1…...
【数据结构】二叉树链式结构——感受递归的暴力美学
前言: 在上篇文章【数据结构】二叉树——顺序结构——堆及其实现中,实现了二叉树的顺序结构,使用堆来实现了二叉树这样一个数据结构;现在就来实现而二叉树的链式结构。 一、链式结构 链式结构,使用链表来表示一颗二叉树…...
开始尝试从0写一个项目--后端(三)
器材管理 和员工管理基本一致,就不赘述,展示代码为主 新增器材 表设计: 字段名 数据类型 说明 备注 id bigint 主键 自增 name varchar(32) 器材名字 img varchar(255) 图片 number BIGINT 器材数量 comment VARC…...
2024年7月解决Docker拉取镜像失败的实用方案,亲测有效
在Ubuntu 16.04、Debian 8、CentOS 7系统中,若遇到Docker拉取镜像失败的问题,以下是一些亲测有效的解决方案: 配置加速地址 首先,创建Docker配置目录:sudo mkdir -p /etc/docker然后,编辑daemon.json文件…...
基于内容的音乐推荐网站/基于ssm的音乐推荐系统/基于协同过滤推荐的音乐网站/基于vue的音乐平台
获取源码联系方式请查看文末🍅 摘 要 随着信息化时代的到来,系统管理都趋向于智能化、系统化,音乐推荐网站也不例外,但目前国内的有些公司仍然都使用人工管理,公司规模越来越大,同时信息量也越来越庞大&…...
STM32智能工业监控系统教程
目录 引言环境准备智能工业监控系统基础代码实现:实现智能工业监控系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景:工业监控与优化问题解决方案与优化收尾与总结 1. 引言 智能工业监控系统通…...
WEB渗透Web突破篇-SQL注入(MYSQL)
注释符 # -- 注意这里有个空格 /* hello */ /*! hello */ /*!32302 10*/ MYSQL version 3.23.02联合查询 得到列数 order by或group by 不断增加数字,直到得到报错响应 1 ORDER BY 1-- #True 1 ORDER BY 2-- #True 1 ORDER BY 3-- #True 1 ORDER BY 4-- #Fal…...
PDF解锁网站
https://smallpdf.com/cn/unlock-pdfhttps://smallpdf.com/cn/unlock-pdfhttps://www.freemypdf.comhttps://www.freemypdf.com...
【Redis】主从复制分析-基础
1 主从节点运行数据的存储 在主从复制中, 对于主节点, 从节点就是自身的一个客户端, 所以和普通的客户端一样, 会被组织为一个 client 的结构体。 typedef struct client {// 省略 } client;同时无论是从节点, 还是主节点, 在运行中的数据都存放在一个 redisServer 的结构体中…...
Transformer自然语言处理实战pdf阅读
一.第一章 欢迎来到transformer的世界 1.解码器-编码器框架 在Transformer出现之前,NLP的最新技术是LSTM等循环架构。这些架 构通过在神经网络连接使用反馈循环,允许信息从一步传播到另一 步,使其成为对文本等序列数据进行建模的理想选择。如…...
Python 高阶语法
前言: 我们通过上篇文章学习了Python的基础语法,接下来我们来学习Python的高阶语法 1.初识对象 在Python中我们可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的 面向对象包含 3 大主要特性: 封装 继承 …...
开始尝试从0写一个项目--前端(三)
器材管理板块 添加器材管理导航 src\views\home\Home.vue src\router\index.js src\views\equipment\Equipment.vue <template><div>hello!</div></template> 测试 搜索导航分页查询 src\views\equipment\Equipment.vue <template><div&…...
Visual stdio code 运行C项目环境搭建
参考 [1]VS Code 配置 C/C 编程运行环境(保姆级教程)_visual studio code c配置-CSDN博客 [2]最新VS code配置C/C环境(tasks.json, launch.json,c_cpp_properties.json)及运行多个文件、配置Cmake_vscode launch.json如何配置-CSDN博客 先装visual stdi…...
免杀笔记 -->API的整理Shellcode加密(过DeFender)
最近更新频率明显下降我懒,那么今天就来记录一下我们的一些常用的API的整理以及ShellCode的加密。 1.WinAPI整理 问我为什么要整理? 就是用起来的时候要左翻右翻 :: 烦死了 1.VirtualAlloc VirtualAlloc(NULL,sizeof(buf),MEM_…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
