haroya01/query-audit
GitHub: haroya01/query-audit
QueryAudit是一个在JUnit测试中自动检测SQL性能问题的工具,帮助在代码上线前发现并修复潜在的生产故障。
Stars: 9 | Forks: 3
# s" and keep it in English. But "Kubernetes Setup" has "Setup" translated. Here, "QueryAudit" might be the full name.
**在测试中捕获SQL性能问题——避免它们影响到生产环境。**
[](https://github.com/haroya01/query-audit/actions/workflows/ci.yml)
[](https://search.maven.org/search?q=g:io.github.haroya01)
[](LICENSE)
[](https://haroya01.github.io/query-audit)
[](https://openjdk.org/)
## 为什么选择 QueryAudit?
大多数SQL性能问题——如N+1查询、缺失索引、不安全的DML操作——在开发期间是隐形的,因为测试数据集很小。它们只会在生产环境中真实负载下浮现,导致服务中断和紧急修复。
**QueryAudit将这一发现过程提前到了你的测试套件中。**
| | 未使用 QueryAudit | 使用 QueryAudit |
|---|---|---|
| **N+1 查询** | 在生产环境中通过缓慢的监控面板发现 | 测试立即失败,并给出确切的查询和修复建议 |
| **缺失索引** | 在表增长到数百万行后才注意到 | 在测试期间通过交叉引用 `SHOW INDEX` / `pg_catalog` 检测到 |
| **不安全的 DML** | 不带 `WHERE` 的 `UPDATE` 在3条测试数据上运行正常 | 在合并前被标记为已确认的问题 |
| **SELECT \*** | 直到表有50列之前都运行正常 | 报告时会建议仅列出需要的列 |
| **反馈循环** | 数天到数周(生产监控) | 秒级(测试执行) |
## 功能概述
QueryAudit 会拦截你在 JUnit 测试期间执行的每一条 SQL 查询,针对 **57 条检测规则** 进行分析,交叉引用数据库的索引元数据,并在发现性能反模式时使构建失败。
- **57 条检测规则**,覆盖 N+1 查询、缺失索引、DML 安全性、锁风险、ORM 反模式等
- **零配置**——只需添加一个注解即可开始
- **可操作的报告**——每个问题都包含 SQL、表、列以及具体的修复建议
- **无生产开销**——仅在测试套件中运行
### 支持的数据库
| 数据库 | 索引元数据来源 | 模块 |
|---|---|---|
| **MySQL** 5.7+ / 8.0+ | `SHOW INDEX` | `query-audit-mysql` |
| **PostgreSQL** 12+ | `pg_catalog` | `query-audit-postgresql` |
## 快速开始
### 1. 添加依赖
#### I think the safest way is to translate the meaning if it's not a proper noun. Let's see the second and third headings: "Gradle (MySQL)" and "Gradle (PostgreSQL)". Here, "Gradle" is a tool, "MySQL" and "PostgreSQL" are databases, so they should be kept in English. The parentheses might be part of the heading.
```
dependencies {
testImplementation 'io.github.haroya01:query-audit-spring-boot-starter:0.3.2'
testImplementation 'io.github.haroya01:query-audit-mysql:0.3.2'
}
```
#### For "Gradle (MySQL)", I should keep "Gradle", "MySQL" in English, and perhaps translate the parentheses or the context. But in Chinese, parentheses are often used as is. The translation might be "Gradle (MySQL)" with no change, but I need to translate to Simplified Chinese.
```
dependencies {
testImplementation 'io.github.haroya01:query-audit-spring-boot-starter:0.3.2'
testImplementation 'io.github.haroya01:query-audit-postgresql:0.3.2'
}
```
io.github.haroya01
query-audit-spring-boot-starter
0.3.2
test
io.github.haroya01
query-audit-mysql
0.3.2
test
```
**PostgreSQL:**
```
io.github.haroya01
query-audit-spring-boot-starter
0.3.2
test
io.github.haroya01
query-audit-postgresql
0.3.2
test
```
#### 不使用 Spring Boot
```
dependencies {
testImplementation 'io.github.haroya01:query-audit-junit5:0.3.2'
testRuntimeOnly 'io.github.haroya01:query-audit-mysql:0.3.2' // or query-audit-postgresql
}
```
### 2. 为你的测试添加注解
```
@SpringBootTest
@QueryAudit
class OrderServiceTest {
@Autowired
private OrderService orderService;
@Test
void findRecentOrders_shouldUseIndex() {
orderService.findRecentOrders(userId);
// QueryAudit automatically analyzes all SQL executed during this test.
// If an N+1 pattern or missing index is detected, the test fails.
}
}
```
### 3. 阅读报告
```
================================================================================
QUERY AUDIT REPORT
OrderServiceTest (8 queries analyzed)
================================================================================
CONFIRMED ISSUES (action required)
────────────────────────────────────────────────────────────────────────────────
[ERROR] N+1 Query Detected
Repeated query: select * from order_items where order_id = ?
Executions: 5 times (threshold: 3)
Suggestion: Use JOIN FETCH or @EntityGraph to load order_items
with the parent query.
[ERROR] Missing Index
Query: select * from order_items where order_id = ?
Table: order_items
Column: order_id
Suggestion: CREATE INDEX idx_order_items_order_id
ON order_items (order_id);
[WARNING] Repeated single-row INSERT should use batch insert
Query: insert into orders (...) values (?, ?, ?)
Table: orders
Detail: Single-row INSERT executed 10 times. Each INSERT causes a
separate network round-trip and log flush.
Suggestion: Use batch INSERT (saveAll() in JPA with hibernate.jdbc.batch_size).
────────────────────────────────────────────────────────────────────────────────
INFO (for review)
────────────────────────────────────────────────────────────────────────────────
[WARNING] SELECT * Usage
Query: select * from orders where user_id = ?
Table: orders
Suggestion: List only the columns you need
================================================================================
3 confirmed issues | 1 info | 8 queries
================================================================================
```
## 57 条检测规则
QueryAudit 包含 57 条检测规则,分为两个置信度层级:
**已确认 (ERROR / WARNING)** —— 基于结构和模式的可靠检查,与测试数据大小无关。它们检查 SQL 文本、重复模式,并交叉引用数据库的实际索引元数据。
**信息 (Info)** —— 基于 EXPLAIN 和启发式检查。可作为早期预警,但可能随数据量变化。
| 类别 | 示例 | 规则数量 |
|---|---|---|
| **N+1 与重复** | N+1 查询、重复的单个 INSERT、可合并的查询 | 3 |
| **缺失索引** | WHERE、JOIN、ORDER BY、GROUP BY、DML 列缺少索引 | 5 |
| **索引误用** | 复合索引前导列、冗余索引、覆盖索引机会、写放大 | 4 |
| **SQL 反模式** | SELECT *、WHERE 中的函数、OR 滥用、OFFSET 分页、LIKE 通配符、隐式类型转换 | 6 |
| **DML 安全** | 无 WHERE 的 UPDATE、无索引的 DML、INSERT 带 SELECT *、INSERT ON DUPLICATE KEY | 6 |
| **连接问题** | 笛卡尔积、过多连接、隐式连接、未使用的连接、关联子查询 | 5 |
| **锁相关** | 无索引的 FOR UPDATE、非唯一索引上的 FOR UPDATE、范围锁风险、INSERT...SELECT 锁定源表 | 4 |
| **查询结构** | DISTINCT 误用、HAVING 误用、不带 ALL 的 UNION、大型 IN 列表、NOT IN 子查询、ORDER BY RAND | 8 |
| **Hibernate / ORM** | 集合删除-重插入、派生删除加载实体、过度获取列 | 3 |
| **MySQL 特有** | FIND_IN_SET、REGEXP 使用、WHERE 中的字符串连接、隐式列 INSERT | 4 |
| **基于 EXPLAIN** | 全表扫描、filesort、临时表 | 3 |
| **其他** | 慢查询、无界结果集、查询数量回归、非确定性分页等 | 6 |
完整的参考请查阅[检测规则概述](https://haroya01.github.io/query-audit/detections/overview/)。
## 注解
| 注解 | 描述 |
|---|---|
| `@QueryAudit` | 完整分析——拦截查询,运行所有 57 条检测规则,遇到已确认问题则失败 |
| `@EnableQueryInspector` | 仅报告模式——运行所有检测但从不使测试失败 |
| `@DetectNPlusOne` | 专注检查——仅当检测到 N+1 查询模式时失败 |
| `@ExpectMaxQueryCount(n)` | 查询预算——如果执行的查询超过 `n` 条则失败 |
## 模块
| 模块 | 描述 |
|---|---|
| `query-audit-core` | 核心分析引擎、检测规则和 SPI 接口 |
| `query-audit-junit5` | JUnit 5 扩展和注解 |
| `query-audit-mysql` | MySQL `SHOW INDEX` 元数据提供程序 |
| `query-audit-postgresql` | 通过 `pg_catalog` 实现的 PostgreSQL `IndexMetadataProvider` |
| `query-audit-spring-boot-starter` | Spring Boot 自动配置 |
## 配置
通过 `application.yml` (Spring Boot) 或编程方式配置:
```
query-audit:
enabled: true
fail-on-detection: true
n-plus-one:
threshold: 3
offset-pagination:
threshold: 1000
or-clause:
threshold: 3
suppress-patterns:
- "select-all"
- "missing-where-index:users.email"
report:
format: console
show-info: true
```
完整的配置选项列表请查阅[配置参考](https://haroya01.github.io/query-audit/guide/configuration/)。
## 文档
完整文档可在 **[query-audit.github.io/query-audit](https://haroya01.github.io/query-audit)** 查阅。
## 许可证
本项目基于 Apache License 2.0 许可——详情请见 [LICENSE](LICENSE) 文件。
Maven
**MySQL:** ```标签:Java开发工具, JS文件枚举, JUnit测试框架, Maven项目管理, N+1查询检测, pocsuite3, SOC Prime, SQL反模式识别, SQL性能测试, 代码质量保证, 域名枚举, 开发工具, 性能优化工具, 持续集成CI, 数据库查询分析, 数据库管理, 测试用例, 测试自动化, 缺失索引检测, 软件测试