Files
nxxmdata/backend/config/query-optimizer.js

246 lines
6.3 KiB
JavaScript
Raw Normal View History

/**
* 数据库查询优化器
* @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
};