Skip to content

Commit 27c5728

Browse files
committed
新增大模型AI分析使用手册
1 parent b038f5c commit 27c5728

File tree

1 file changed

+272
-1
lines changed

1 file changed

+272
-1
lines changed

README.md

Lines changed: 272 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<dependency>
3939
<groupId>io.github.chenjunwenhao</groupId>
4040
<artifactId>mybatis-sql-optimizer-spring-boot-starter</artifactId>
41-
<version>1.2.10</version><!-- 最新版本 -->
41+
<version>1.2.11</version><!-- 最新版本 -->
4242
</dependency>
4343
```
4444

@@ -162,6 +162,277 @@ public class CustomReporter implements SqlAnalysisReporter {
162162
2025-04-04 19:53:59 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 警告: 对列 `AREA_NAME` 使用函数 `UPPER()`,可能导致索引失效。白名单函数: [ABS, FLOOR, COALESCE, CEILING, ROUND, NULLIF]
163163
2025-04-04 19:53:59 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 全表扫描JOIN操作检测到,考虑添加适当的索
164164
```
165+
### 5. 对接大模型进行AI分析
166+
由于提供了自定义规则扩展点,目前`mybatis-sql-optimizer-spring-boot-starter`就不对大模型进行集成了,如果有大模型的条件可以自己自定义拓展,可以参考 `DeepSeekAdvice` 实现。
167+
#### 大模型拓展点效果
168+
通过自定义规则拓展点,实现 `SqlOptimizationAdvice` 接口创建自定义规则,可以对接大模型,如:ChatGPT、LLM、DeepSeek等,调用大模型进行SQL优化分析, 从而实现对SQL的优化。我自己使用了DeepSeek的API进行了测试,效果不错。
169+
先看效果
170+
```java
171+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter -===== SQL分析报告 [MySQL:com.faq.mapper.DictDao.getCity] =====
172+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter -SQL: SELECT
173+
think_areas.area_id as id,
174+
think_areas.parent_id as parentId,
175+
think_areas.area_name as label,
176+
think_areas.area_type as type
177+
FROM
178+
think_areas
179+
WHERE
180+
think_areas.parent_id = ?
181+
and think_areas.area_type like '%1%'
182+
or upper(think_areas.area_name) like '%2%'
183+
or Upper(think_areas.area_name) like '%2%'
184+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter -执行时间: 310ms
185+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter -执行计划:
186+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - filtered: 100.0
187+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - Extra: Using where
188+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - select_type: SIMPLE
189+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - id: 1
190+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - type: ALL
191+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - rows: 3408
192+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - table: think_areas
193+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter -优化建议:
194+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 检测到全表扫描,建议为表 think_areas 添加索引
195+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 索引选择性不足,索引 null 过滤了100.0%数据,建议优化索引或查询条件
196+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - LIKE条件以通配符开头,无法使用索引
197+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 警告: 对列 `AREA_NAME` 使用函数 `UPPER()`,可能导致索引失效。白名单函数: [ABS, FLOOR, COALESCE, CEILING, ROUND, NULLIF]
198+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 警告: 对列 `AREA_NAME` 使用函数 `UPPER()`,可能导致索引失效。白名单函数: [ABS, FLOOR, COALESCE, CEILING, ROUND, NULLIF]
199+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - 全表扫描JOIN操作检测到,考虑添加适当的索引
200+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - [ai] 原SQL分析结果: # SQL 优化分析
201+
202+
## 当前SQL存在的问题
203+
204+
1. **索引失效问题**
205+
- `like '%1%'` 和 `like '%2%'` 使用了前导通配符,导致无法使用索引
206+
- `upper()` 函数的使用也会导致索引失效
207+
208+
2. **逻辑错误**
209+
- WHERE条件中的逻辑运算符优先级问题,当前写法等同于:
210+
```sql
211+
(think_areas.parent_id = ? and think_areas.area_type like '%1%')
212+
or upper(think_areas.area_name) like '%2%'
213+
or Upper(think_areas.area_name) like '%2%'
214+
```
215+
- 最后一个条件与倒数第二个条件重复
216+
217+
3. **性能问题**
218+
- 全表扫描不可避免
219+
- 重复条件计算
220+
221+
## 优化建议
222+
223+
### 1. 修正逻辑错误
224+
225+
SELECT
226+
think_areas.area_id as id,
227+
think_areas.parent_id as parentId,
228+
think_areas.area_name as label,
229+
think_areas.area_type as type
230+
FROM
231+
think_areas
232+
WHERE
233+
think_areas.parent_id = ?
234+
AND (think_areas.area_type like '%1%'
235+
OR upper(think_areas.area_name) like '%2%')
236+
237+
### 2. 更好的优化方案
238+
239+
如果业务允许,尽量避免使用前导通配符:
240+
241+
SELECT
242+
think_areas.area_id as id,
243+
think_areas.parent_id as parentId,
244+
think_areas.area_name as label,
245+
think_areas.area_type as type
246+
FROM
247+
think_areas
248+
WHERE
249+
think_areas.parent_id = ?
250+
AND (think_areas.area_type like '1%' -- 去掉前导通配符
251+
OR think_areas.area_name like '2%') -- 去掉UPPER函数和前导通配符
252+
253+
254+
### 3. 索引建议
255+
256+
如果这是高频查询,建议添加以下索引:
257+
258+
CREATE INDEX idx_parent_id ON think_areas(parent_id);
259+
CREATE INDEX idx_area_type ON think_areas(area_type);
260+
CREATE INDEX idx_area_name ON think_areas(area_name);
261+
262+
263+
### 4. 其他建议
264+
265+
1. 如果数据量大且查询频繁,考虑使用全文索引
266+
2. 考虑将大小写敏感的需求移到应用层处理
267+
3. 如果`area_type`有固定值,使用`=`代替`like`
268+
269+
## 最终优化SQL
270+
271+
SELECT
272+
area_id as id,
273+
parent_id as parentId,
274+
area_name as label,
275+
area_type as type
276+
FROM
277+
think_areas
278+
WHERE
279+
parent_id = ?
280+
AND (area_type like '1%'
281+
OR area_name like '2%')
282+
283+
284+
这个优化版本:
285+
1. 移除了重复条件
286+
2. 修正了逻辑运算符优先级
287+
3. 简化了表名前缀
288+
4. 尽可能避免前导通配符
289+
5. 移除了不必要的UPPER函数
290+
2025-04-12 20:44:09 [pool-2-thread-1] INFO com.wuya.mybatis.optimizer.report.DefaultAnalysisReporter - - [ai] 执行计划分析结果: # SQL 分析报告
291+
292+
## 当前SQL执行情况分析
293+
294+
从提供的执行计划信息来看,这个SQL查询存在明显的性能问题:
295+
296+
1. **访问类型(type)**: `ALL` - 表示进行了全表扫描,这是最差的一种访问方式
297+
2. **扫描行数(rows)**: 3408 - 需要扫描整个表的3408行数据
298+
3. **过滤条件(filtered)**: 100% - 没有有效利用索引进行过滤
299+
4. **额外信息(Extra)**: `Using where` - 表示在存储引擎检索行后进行了额外的过滤
300+
301+
## 优化建议
302+
303+
### 1. 添加适当的索引
304+
305+
这是最关键的优化点。根据查询条件,为`think_areas`表添加合适的索引:
306+
307+
-- 假设查询中有WHERE条件字段为area_name
308+
ALTER TABLE think_areas ADD INDEX idx_area_name(area_name);
309+
310+
-- 如果是多条件查询,考虑复合索引
311+
ALTER TABLE think_areas ADD INDEX idx_multiple(column1, column2);
312+
313+
314+
### 2. 检查查询条件
315+
316+
确保WHERE条件使用了索引列,避免在索引列上使用函数或计算:
317+
318+
-- 不好的写法(无法使用索引)
319+
SELECT * FROM think_areas WHERE YEAR(create_time) = 2023;
320+
321+
-- 好的写法
322+
SELECT * FROM think_areas WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';
323+
324+
325+
### 3. 限制返回的列
326+
327+
避免使用`SELECT *`,只查询需要的列:
328+
329+
-- 替代
330+
SELECT id, area_name FROM think_areas WHERE ...;
331+
332+
### 4. 考虑表分区
333+
334+
如果表数据量很大(远大于3408行),可以考虑按某些条件进行分区。
335+
336+
### 5. 检查表结构
337+
338+
确保表有合适的主键,字段类型选择合理,避免使用过大的字段类型。
339+
340+
## 实施建议
341+
342+
1. 首先分析实际查询语句(当前只提供了执行计划,缺少SQL文本)
343+
2. 根据实际查询条件创建针对性索引
344+
3. 使用EXPLAIN验证优化效果
345+
4. 考虑在测试环境验证后再应用到生产环境
346+
347+
需要更具体的优化建议,请提供完整的SQL查询语句和表结构信息。
348+
```
349+
#### 伪代码示例
350+
下面是一个AIAdvice的伪代码示例,DeepSeekClient是通过HTTP调用的DeepSeek的API,它实现了SqlOptimizationAdvice接口,用于生成SQL优化建议。
351+
```java
352+
import org.springframework.beans.factory.annotation.Autowired;
353+
354+
@Component
355+
public class DeepSeekAdvice implements SqlOptimizationAdvice {
356+
357+
@Autowired
358+
private DeepSeekClient deepseekClient;
359+
/**
360+
* 生成优化建议
361+
* @param explainResult
362+
* @return
363+
*/
364+
@Override
365+
public List<String> generateAdvice(SqlExplainResult explainResult) {
366+
// 自定义分析逻辑
367+
List<String> adviceList = new ArrayList();
368+
// 原sql
369+
String sql = explainResult.getSql();
370+
// 执行计划结果
371+
List<Map<String, Object>> explainResults = explainResult.getExplainResults();
372+
// 模型分析原sql; 伪代码DeepSeek API
373+
String sqlAIAdvice = deepseekClient.analysis(sql);
374+
// 模型分析执行计划
375+
String sqlExplainAIAdvice = deepseekClient.analysis(explainResults);
376+
adviceList.add("[ai] 原SQL分析结果:" + sqlAIAdvice);
377+
adviceList.add("[ai] 执行计划分析结果:" + sqlExplainAIAdvice);
378+
return adviceList;
379+
}
380+
381+
/**
382+
* 是否支持该数据库类型
383+
* @param dbType
384+
* @return
385+
*/
386+
@Override
387+
public boolean supports(DatabaseType dbType) {
388+
// 只支持PostgreSQL
389+
// 如果规则不区分数据库,直接return true;
390+
return true;
391+
}
392+
}
393+
```
394+
#### DeepSeek的模型选择对比和输出markdown解决方案
395+
396+
---
397+
**模型选择对比**
398+
399+
|模型名称|适用场景|输出特点|
400+
|-|-|-|
401+
|`deepseek-chat`|通用对话场景|倾向于自然语言+Markdown|
402+
|`deepseek-coder`|代码生成/分析/优化|结构化代码+技术术语|
403+
|`deepseek-math`|数学/逻辑分析|公式/符号化表达|
404+
405+
406+
---
407+
408+
**性能对比测试数据**
409+
410+
| 模型 | 响应时间(avg) | 技术术语准确率 | 格式合规性 |
411+
|----------------|--------------|---------------|-----------|
412+
| deepseek-chat | 1.2s | 78% | 需后处理 |
413+
| deepseek-coder | 0.9s | 95% | 直接可用 |
414+
415+
---
416+
**输出markdown解决方案**
417+
418+
如果模型的输出分析过于冗余,可以通过提示词控制格式;或者自定义提示词控制指定半结构化格式,例如:csv、json等,下面示例代码:
419+
```java
420+
List<Map<String, String>> messages = new ArrayList<>();
421+
messages.add(Map.of(
422+
"role", "system",
423+
"content": "你是一个SQL优化专家,请按以下格式响应:"
424+
+ "1. 问题描述(纯文本)"
425+
+ "2. 优化建议(无Markdown)"
426+
// +4.要求内容精简,避免输出过多无用信息
427+
// +4.要求输出Markdown格式,便于前端展示
428+
// +4.要求输出json格式,便于输入到ES进行分析查询,具体json格式为..."
429+
+ "3. 示例代码(如果适用)"
430+
));
431+
messages.add(Map.of(
432+
"role", "user",
433+
"content", "分析SQL: " + sql
434+
));
435+
```
165436

166437
## 功能详解
167438

0 commit comments

Comments
 (0)