1. 项目背景与问题定位
工单系统作为企业IT服务管理的核心组件,承载着1000名工人的日常任务分配、进度跟踪和问题处理。随着业务量增长,系统响应速度从最初的毫秒级逐渐恶化到5-8秒,特别是在高峰期出现大量"工单状态更新超时"的报错。通过监控平台发现,数据库服务器CPU长期维持在90%以上,慢查询日志中频繁出现执行时间超过3秒的SQL语句。
典型问题SQL示例:
sql复制SELECT * FROM work_order
WHERE assignee_id = 12345
AND status IN ('processing', 'pending')
AND created_at > '2023-06-01'
ORDER BY priority DESC;
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 索引优化实战
2.1 现有索引分析
使用SHOW INDEX FROM work_order检查发现,当前仅存在主键id的单列索引。通过EXPLAIN分析上述查询:
code复制+----+-------------+------------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE | work_order | ALL | NULL | NULL | NULL | NULL | 287543 | Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+--------+----------------+
2.2 联合索引设计
根据最左前缀原则和字段区分度,设计复合索引:
sql复制ALTER TABLE work_order ADD INDEX idx_assignee_status_created (assignee_id, status, created_at);
关键设计考量:
- assignee_id作为首个字段,因其在WHERE条件中精确匹配且区分度高(1000个不同值)
- status字段虽然区分度低(5种状态),但满足最左前缀的第二个条件
- created_at作为范围查询字段放在最后,避免中断索引使用
2.3 索引效果验证
优化后EXPLAIN结果:
code复制+----+-------------+------------+-------+---------------------------+---------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------------------+---------------------------+---------+------+------+-------------+
| 1 | SIMPLE | work_order | range | idx_assignee_status_created| idx_assignee_status_created| 772 | NULL | 243 | Using where |
+----+-------------+------------+-------+---------------------------+---------------------------+---------+------+------+-------------+
执行时间从4.7秒降至0.02秒,扫描行数从28万减少到243行。
3. 慢查询深度排查
3.1 慢查询日志配置
启用完整慢查询监控:
sql复制SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;
3.2 典型问题案例
案例一:隐式类型转换
sql复制SELECT * FROM work_order WHERE assignee_id = '1001'; -- 字符串与整型比较
优化方案:统一使用正确数据类型
sql复制SELECT * FROM work_order WHERE assignee_id = 1001;
案例二:OR条件导致索引失效
sql复制SELECT * FROM work_order
WHERE status = 'completed' OR priority > 3;
优化为UNION查询:
sql复制SELECT * FROM work_order WHERE status = 'completed'
UNION
SELECT * FROM work_order WHERE priority > 3;
3.3 执行计划分析技巧
重点关注EXPLAIN的以下指标:
- type列:至少达到range级别,理想是ref或eq_ref
- rows列:预估扫描行数应与实际返回量级相当
- Extra列:避免出现"Using filesort"、"Using temporary"
4. 系统级优化措施
4.1 数据库参数调优
关键my.cnf配置调整:
code复制innodb_buffer_pool_size = 8G # 调整为物理内存的70%
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 2 # 非金融场景可放宽
query_cache_type = 0 # 高并发下禁用查询缓存
4.2 表结构优化
- 将大文本字段分离到单独表:
sql复制CREATE TABLE work_order_details (
id BIGINT PRIMARY KEY,
description TEXT,
FULLTEXT INDEX idx_desc (description)
) ENGINE=InnoDB;
- 对枚举类型使用TINYINT代替VARCHAR:
sql复制ALTER TABLE work_order
MODIFY COLUMN status TINYINT COMMENT '1-待处理 2-处理中 3-已完成';
5. 持续监控体系
5.1 监控看板配置
- Prometheus监控指标:
- mysql_global_status_slow_queries
- mysql_global_status_innodb_row_lock_waits
- Grafana展示:
- 慢查询趋势图
- 索引命中率
- 锁等待时间
5.2 自动化处理流程
python复制# 慢查询自动分析脚本示例
def analyze_slow_query(log_entry):
if 'filesort' in log_entry['extra']:
suggest_add_index(log_entry['table'], log_entry['condition_fields'])
if 'implicit_conversion' in log_entry['warning']:
alert_data_type_mismatch(log_entry['field'])
6. 避坑指南
- 过度索引陷阱:每个新增索引会增加约5%的写入开销,建议单表索引不超过5个
- 统计信息不准:大数据量变更后执行
ANALYZE TABLE work_order - 连接池配置:确保max_connections与应用连接池大小匹配,避免连接风暴
- 分页查询优化:避免使用
LIMIT 10000,10,改为基于游标的分页sql复制SELECT * FROM work_order WHERE id > 10000 AND status = 'processing' ORDER BY id LIMIT 10;
通过3周的持续优化,系统平均响应时间从4.3秒降至120毫秒,数据库CPU使用率稳定在30%以下。最关键的经验是:索引优化必须结合具体查询模式,没有放之四海皆准的方案。建议每季度进行一次全面的SQL审计,及时清理低效查询。
