上一篇
数据库卡顿怎么办
- 数据库
- 2025-08-25
- 7
索引、清理冗余数据、调整配置参数、升级硬件,必要时分区或分库以缓解
初步诊断:定位问题根源
监控资源使用情况
- CPU利用率过高:可能是由于复杂查询、索引缺失或锁竞争导致,通过
top/htop(Linux)或任务管理器(Windows)查看进程占用;在数据库层面执行类似SELECT FROM v$session WHERE program LIKE '%sqlplus%'(Oracle示例)识别高消耗的SQL语句。 - 内存不足:检查SWAP分区是否被频繁换入换出(可用
free -m命令),若存在大量磁盘I/O等待,则说明物理内存不够支撑缓存需求,数据库配置参数如SGA_MAX_SIZE(Oracle)、shared_buffers(PostgreSQL)可能需要调整。 - 磁盘I/O瓶颈:使用工具如
iostat观察读写延迟和队列长度,机械硬盘尤其容易成为性能短板,考虑升级为SSD或分布式存储架构。 - 网络延迟:跨机房部署时,客户端与服务器间的RTT(往返时延)超过阈值会影响响应速度,可通过抓包工具(tcpdump)验证数据传输效率。
分析慢查询日志
大多数数据库支持记录执行时间超过特定阈值的SQL语句:
- MySQL: 开启
slow_query_log=ON并设置long_query_time=1秒;解析日志文件可发现全表扫描(Type=ALL)、无索引驱动的顺序访问等问题。 - PostgreSQL: 通过
pgbadger可视化工具生成统计报告,重点标记出排序操作占比高的语句。 - SQL Server: 使用动态管理视图
sys.dm_exec_query_stats获取历史执行计划。
检查锁争用与事务阻塞
长时间未提交的大事务会持有大量锁资源,阻碍其他会话正常读写。
- 在MySQL中运行
SHOW PROCESSLIST;查找处于”Locked”状态的连接; - Oracle可通过
V$LOCKED_OBJECT视图定位被锁定的对象及发起方; - SQL Server则用
sp_who2存储过程查看死锁图示。
针对性优化方案
| 维度 | 具体措施 | 适用场景举例 |
|---|---|---|
| 索引策略 | 为WHERE子句中的过滤条件创建单列/复合索引 ️避免过度索引导致写入惩罚 |
订单表按用户ID+创建时间范围查询历史记录 |
| SQL改写 | ️ 替换子查询为JOIN操作 ️减少函数调用在WHERE中的使用(如LENGTH()会使索引失效) |
SELECT FROM logs WHERE TO_CHAR(ts)=... →改用范围条件 |
| 分区表设计 | ️按时间范围(月/季度)或地域哈希分散热点数据 | 千亿级日志系统的归档分层存储 |
| 连接池管理 | 复用数据库连接而非每次新建关闭,控制最大活跃连接数防止上下文切换开销 | Web应用Tomcat容器配置HikariCP替代默认驱动 |
| 硬件扩容 | 纵向扩展(增加单机CPU核数、内存容量)VS横向扩展(读写分离集群、Sharding分片) | 电商瞬秒场景采用主从复制+中间件路由读写请求 |
典型错误案例修正对比:
原始低效写法:

SELECT FROM large_table WHERE status = 'processed' AND create_time < NOW() INTERVAL 7 DAY;
优化后版本:
-确保(status, create_time)存在联合索引 EXPLAIN ANALYZE SELECT id, content FROM large_table FORCE INDEX (idx_status_time) ... ;
通过强制走指定索引并仅选取必要字段,减少回表次数。
高级调优技巧
执行计划解读
使用EXPLAIN家族命令深入理解优化器的决策逻辑:

- Cost Based Optimizer (CBO):基于统计信息预估各种路径的成本值;若实际行数与预估偏差过大,需更新直方图统计数据。
- Full Table Scan警示:当rows examined远大于rows returned时,提示缺乏有效过滤机制。
- Nested Loop Join嵌套循环连接适用于小数据集,而Hash Join更适合大表关联。
临时表妙用
对于多阶段处理流程,适时将中间结果存入临时表能显著降低整体复杂度:
CREATE TEMPORARY TABLE temp_result AS SELECT subquery_part1 UNION ALL subquery_part2; ANALYZE TABLE temp_result COMPUTE STATISTICS; -更新统计信息供后续优化
物化视图加速报表类请求
预先计算聚合结果并定期刷新,特别适合BI分析场景:
CREATE MATERIALIZED VIEW sales_summary AS SELECT region, SUM(amount) FROM transactions GROUP BY region;
运维体系构建
自动化监控告警设置建议:
| 指标 | 阈值建议 | 触发动作 |
|---|---|---|
| CPU持续>80%超过5分钟 | >80% | 发送PagerDuty通知+自动扩容预案 |
| 活跃连接数突增 | >设定最大值的90% | 限制新连接+邮件预警 |
| 主从同步延迟 | >1秒 | 切换备库接管读流量 |
版本迭代注意事项:
- 重大DDL变更放在业务低谷期执行;
- 使用在线重构工具(如Percona Online Schema Change for MySQL);
- Gray发布策略逐步推送新版本到生产环境。
相关问答FAQs
Q1: 如果已经做了所有索引但某些查询仍然很慢怎么办?
A: 此时应考虑以下几点:①检查是否有函数包装导致索引失效(如对字段进行表达式运算);②确认统计数据是否过时,执行ANALYZE TABLE ...更新;③尝试改写SQL结构,例如用EXISTS代替IN子句;④对于超大分页场景(如第10万条之后的记录),可采用游标或基于游标的分页方案替代传统的LIMIT offset方式。

Q2: 如何判断是否需要做数据库分库分表?
A: 当出现以下迹象时建议实施水平拆分:①单表数据量超过千万级且QPS持续增长;②单个库实例难以承载并发压力(表现为频繁超时);③热点数据集中在某些分区导致局部过热,可采用一致性哈希算法实现均匀分布,配合中间件层实现透明的路由转发,例如用户ID取模分配到不同物理节点,同时保留全局
