UNPKG

quicklite

Version:

A lightweight ORM toolkit for SQLite in Node.js applications

202 lines (153 loc) 5.88 kB
# 查询分析器 (QueryAnalyzer) `QueryAnalyzer` 是一个用于分析 SQLite 查询性能并提供优化建议的工具类。它可以帮助开发者识别低效查询、检测全表扫描、分析索引使用情况,并为复杂查询提供索引建议。 > 兼容 better-sqlite3 v11.8.1 和 SQLite 3.48.0 ## 功能特性 1. **查询执行计划分析**:解析 SQLite EXPLAIN QUERY PLAN 输出,识别可能的性能问题 2. **索引使用检测**:检查查询是否正在使用可用索引,识别索引扫描和表扫描 3. **性能建议生成**:根据查询结构和表结构生成优化建议 4. **执行时间测量**:测量查询执行时间,帮助识别慢查询 5. **索引建议**:基于查询模式自动建议创建索引 ## 基本用法 ### 分析 SQL 查询 ```typescript import { QueryAnalyzer } from 'quicklite'; import Database from 'better-sqlite3'; const db = new Database('myapp.db'); // 分析简单查询 const analysis = QueryAnalyzer.analyze( db, 'SELECT * FROM users WHERE age > 30' ); console.log('查询:', analysis.sql); console.log('执行时间:', analysis.executionTime, 'ms'); console.log('查询计划:'); analysis.queryPlan.forEach(p => { console.log(`- ${p.detail}`); }); console.log('性能建议:'); analysis.suggestions.forEach(s => { console.log(`- ${s}`); }); // 分析带参数的查询 const paramQueryAnalysis = QueryAnalyzer.analyze( db, 'SELECT * FROM users WHERE email = ?', ['user@example.com'] ); ``` ### 获取索引建议 ```typescript // 获取复杂查询的索引建议 const indexSuggestions = QueryAnalyzer.suggestIndices( db, `SELECT u.name, o.product, SUM(o.amount) as total FROM users u JOIN orders o ON u.id = o.user_id WHERE u.age > 30 GROUP BY u.id, o.product ORDER BY total DESC` ); console.log('建议为以下列创建索引:'); indexSuggestions.forEach(s => { console.log(`- ${s}`); }); ``` ## API 参考 ### QueryAnalyzer 类 #### 静态方法 - **analyze(db: Database, sql: string, params?: any[]): QueryAnalysisResult** 分析 SQL 查询并返回详细的分析结果。 参数: - `db`: Better-SQLite3 数据库实例 - `sql`: 要分析的 SQL 查询语句 - `params` (可选): 查询的参数值 返回: 包含查询计划、执行时间和优化建议的 `QueryAnalysisResult` 对象 - **analyzePlan(queryPlan: QueryPlan[], sql: string): string[]** 根据查询计划生成优化建议。 参数: - `queryPlan`: 查询计划数组 - `sql`: SQL 查询语句 返回: 优化建议字符串数组 - **extractTableNames(sql: string): string[]** 从 SQL 查询中提取表名。 参数: - `sql`: SQL 查询语句 返回: 表名字符串数组 - **suggestIndices(db: Database, sql: string): string[]** 为给定的 SQL 查询建议可能的索引。 参数: - `db`: Better-SQLite3 数据库实例 - `sql`: SQL 查询语句 返回: 索引建议字符串数组 ### 类型定义 ```typescript // 查询计划项 interface QueryPlan { id: number; parentId: number | null; detail: string; } // 查询分析结果 interface QueryAnalysisResult { sql: string; queryPlan: QueryPlan[]; executionTime: number; suggestions: string[]; } ``` ## 性能建议类型 QueryAnalyzer 可以提供多种类型的性能建议,包括但不限于: 1. **缺少索引建议**:当查询包含 WHERE、JOIN 或 ORDER BY 子句但没有相应索引时 2. **全表扫描警告**:当查询需要扫描整个表而不是使用索引时 3. **临时表使用提醒**:当查询需要创建临时表进行排序或分组时 4. **复合索引建议**:当查询中的多个条件可以通过单个复合索引优化时 5. **查询重构建议**:推荐可能更高效的查询写法 ## 最佳实践 1. **定期分析关键查询**:使用 QueryAnalyzer 定期检查应用中最常用和最复杂的查询 2. **验证索引效果**:添加建议的索引后,再次使用 QueryAnalyzer 分析以确认性能改进 3. **在开发阶段使用**:尽早发现并解决性能问题,而不是等到生产环境 4. **权衡索引数量**:添加索引会提高查询速度,但也会增加写入开销和存储空间,需要合理平衡 ## 示例应用场景 ### 优化数据报表查询 ```typescript // 分析复杂的报表查询 const reportQueryAnalysis = QueryAnalyzer.analyze( db, `SELECT u.department, COUNT(DISTINCT u.id) as userCount, SUM(o.amount) as totalAmount FROM users u LEFT JOIN orders o ON u.id = o.userId WHERE u.joinDate > ? GROUP BY u.department ORDER BY totalAmount DESC`, [Date.now() - 90 * 24 * 60 * 60 * 1000] // 过去90天 ); // 应用建议的索引 reportQueryAnalysis.suggestions .filter(s => s.includes('考虑为以下列创建索引')) .forEach(suggestion => { const match = suggestion.match(/为\s+(\w+)\.(\w+)\s+创建索引/); if (match) { const [_, table, column] = match; const indexName = `idx_${table}_${column}`; db.exec(`CREATE INDEX IF NOT EXISTS ${indexName} ON ${table}(${column})`); console.log(`已创建索引: ${indexName}`); } }); ``` ### 监控应用查询性能 ```typescript // 在应用中集成查询监控 function monitorQuery(db, sql, params = []) { const analysis = QueryAnalyzer.analyze(db, sql, params); // 记录耗时超过100ms的查询 if (analysis.executionTime > 100) { logger.warn(`慢查询检测: ${sql}`); logger.warn(`执行时间: ${analysis.executionTime}ms`); logger.warn(`优化建议: ${analysis.suggestions.join('\n')}`); } return db.prepare(sql).all(params); } ```