Initial commit: 宁夏智慧养殖监管平台
This commit is contained in:
246
backend/config/query-optimizer.js
Normal file
246
backend/config/query-optimizer.js
Normal file
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* 数据库查询优化器
|
||||
* @file query-optimizer.js
|
||||
* @description 监控和优化SQL查询性能
|
||||
*/
|
||||
const { sequelize } = require('./database-pool');
|
||||
const { QueryTypes } = require('sequelize');
|
||||
|
||||
/**
|
||||
* 记录查询性能
|
||||
* @param {string} query SQL查询语句
|
||||
* @param {number} executionTime 执行时间(毫秒)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function logQueryPerformance(query, executionTime) {
|
||||
try {
|
||||
// 简化查询语句(移除参数值)
|
||||
const simplifiedQuery = query.replace(/('([^']*)'|"([^"]*)"|`([^`]*)`)/g, '?');
|
||||
|
||||
// 记录到性能日志表
|
||||
await sequelize.query(
|
||||
'INSERT INTO query_performance_logs (query, execution_time, timestamp) VALUES (?, ?, NOW())',
|
||||
{
|
||||
replacements: [simplifiedQuery, executionTime],
|
||||
type: QueryTypes.INSERT
|
||||
}
|
||||
).catch(() => {
|
||||
// 如果表不存在,创建表
|
||||
return sequelize.query(
|
||||
`CREATE TABLE IF NOT EXISTS query_performance_logs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
query TEXT NOT NULL,
|
||||
execution_time FLOAT NOT NULL,
|
||||
timestamp DATETIME NOT NULL,
|
||||
INDEX (timestamp),
|
||||
INDEX (execution_time)
|
||||
)`,
|
||||
{ type: QueryTypes.RAW }
|
||||
).then(() => {
|
||||
// 重新尝试插入
|
||||
return sequelize.query(
|
||||
'INSERT INTO query_performance_logs (query, execution_time, timestamp) VALUES (?, ?, NOW())',
|
||||
{
|
||||
replacements: [simplifiedQuery, executionTime],
|
||||
type: QueryTypes.INSERT
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('记录查询性能失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别慢查询
|
||||
* @param {number} threshold 慢查询阈值(毫秒),默认为500ms
|
||||
* @returns {Promise<Array>} 慢查询列表
|
||||
*/
|
||||
async function identifySlowQueries(threshold = 500) {
|
||||
try {
|
||||
// 查询性能日志表中的慢查询
|
||||
const slowQueries = await sequelize.query(
|
||||
'SELECT query, AVG(execution_time) as avg_time, COUNT(*) as count, MAX(timestamp) as last_seen ' +
|
||||
'FROM query_performance_logs ' +
|
||||
'WHERE execution_time > ? ' +
|
||||
'GROUP BY query ' +
|
||||
'ORDER BY avg_time DESC',
|
||||
{
|
||||
replacements: [threshold],
|
||||
type: QueryTypes.SELECT
|
||||
}
|
||||
).catch(() => {
|
||||
// 如果表不存在,返回空数组
|
||||
return [];
|
||||
});
|
||||
|
||||
return slowQueries;
|
||||
} catch (error) {
|
||||
console.error('识别慢查询失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析和优化表
|
||||
* @param {string} tableName 表名
|
||||
* @returns {Promise<Object>} 优化结果
|
||||
*/
|
||||
async function analyzeAndOptimizeTable(tableName) {
|
||||
try {
|
||||
// 分析表
|
||||
await sequelize.query(`ANALYZE TABLE ${tableName}`, { type: QueryTypes.RAW });
|
||||
|
||||
// 优化表
|
||||
const optimizeResult = await sequelize.query(`OPTIMIZE TABLE ${tableName}`, { type: QueryTypes.RAW });
|
||||
|
||||
return optimizeResult[0];
|
||||
} catch (error) {
|
||||
console.error(`分析和优化表 ${tableName} 失败:`, error);
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表的索引信息
|
||||
* @param {string} tableName 表名
|
||||
* @returns {Promise<Array>} 索引信息
|
||||
*/
|
||||
async function getIndexInfo(tableName) {
|
||||
try {
|
||||
const indexInfo = await sequelize.query(
|
||||
'SHOW INDEX FROM ??',
|
||||
{
|
||||
replacements: [tableName],
|
||||
type: QueryTypes.SELECT
|
||||
}
|
||||
);
|
||||
|
||||
return indexInfo;
|
||||
} catch (error) {
|
||||
console.error(`获取表 ${tableName} 的索引信息失败:`, error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表信息
|
||||
* @param {string} tableName 表名
|
||||
* @returns {Promise<Object>} 表信息
|
||||
*/
|
||||
async function getTableInfo(tableName) {
|
||||
try {
|
||||
// 获取表状态
|
||||
const tableStatus = await sequelize.query(
|
||||
'SHOW TABLE STATUS LIKE ?',
|
||||
{
|
||||
replacements: [tableName],
|
||||
type: QueryTypes.SELECT
|
||||
}
|
||||
);
|
||||
|
||||
// 获取表结构
|
||||
const tableStructure = await sequelize.query(
|
||||
'DESCRIBE ??',
|
||||
{
|
||||
replacements: [tableName],
|
||||
type: QueryTypes.SELECT
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
status: tableStatus[0] || {},
|
||||
structure: tableStructure
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`获取表 ${tableName} 信息失败:`, error);
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解释查询计划
|
||||
* @param {Object} query Sequelize查询对象
|
||||
* @returns {Promise<Array>} 查询计划
|
||||
*/
|
||||
async function explainQuery(query) {
|
||||
try {
|
||||
// 获取SQL语句
|
||||
const sql = query.getQueryString();
|
||||
|
||||
// 执行EXPLAIN
|
||||
const explainResult = await sequelize.query(
|
||||
`EXPLAIN ${sql}`,
|
||||
{
|
||||
type: QueryTypes.SELECT
|
||||
}
|
||||
);
|
||||
|
||||
return explainResult;
|
||||
} catch (error) {
|
||||
console.error('解释查询计划失败:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库状态
|
||||
* @returns {Promise<Object>} 数据库状态
|
||||
*/
|
||||
async function getDatabaseStatus() {
|
||||
try {
|
||||
// 获取全局状态
|
||||
const globalStatus = await sequelize.query(
|
||||
'SHOW GLOBAL STATUS',
|
||||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
|
||||
// 转换为对象格式
|
||||
const status = {};
|
||||
globalStatus.forEach(item => {
|
||||
if (item.Variable_name && item.Value) {
|
||||
status[item.Variable_name] = item.Value;
|
||||
}
|
||||
});
|
||||
|
||||
// 提取关键指标
|
||||
return {
|
||||
connections: {
|
||||
max_used: status.Max_used_connections,
|
||||
current: status.Threads_connected,
|
||||
running: status.Threads_running,
|
||||
created: status.Threads_created,
|
||||
cached: status.Threads_cached
|
||||
},
|
||||
queries: {
|
||||
total: status.Questions,
|
||||
slow: status.Slow_queries,
|
||||
qps: status.Queries
|
||||
},
|
||||
buffer_pool: {
|
||||
size: status.Innodb_buffer_pool_pages_total,
|
||||
free: status.Innodb_buffer_pool_pages_free,
|
||||
dirty: status.Innodb_buffer_pool_pages_dirty,
|
||||
reads: status.Innodb_buffer_pool_reads,
|
||||
read_requests: status.Innodb_buffer_pool_read_requests,
|
||||
hit_rate: status.Innodb_buffer_pool_read_requests && status.Innodb_buffer_pool_reads
|
||||
? (1 - parseInt(status.Innodb_buffer_pool_reads) / parseInt(status.Innodb_buffer_pool_read_requests)) * 100
|
||||
: 0
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取数据库状态失败:', error);
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
logQueryPerformance,
|
||||
identifySlowQueries,
|
||||
analyzeAndOptimizeTable,
|
||||
getIndexInfo,
|
||||
getTableInfo,
|
||||
explainQuery,
|
||||
getDatabaseStatus
|
||||
};
|
||||
Reference in New Issue
Block a user