MySQL SQL 调优完整指南

SQL 调优是一个系统性工程,需要从发现问题解决问题的全流程掌握。下面从方法论到具体技巧详细讲解。

一、调优流程图

#mermaid-svg-gqtm0fChI78T9LYT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gqtm0fChI78T9LYT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gqtm0fChI78T9LYT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gqtm0fChI78T9LYT .error-icon{fill:#552222;}#mermaid-svg-gqtm0fChI78T9LYT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gqtm0fChI78T9LYT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gqtm0fChI78T9LYT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gqtm0fChI78T9LYT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gqtm0fChI78T9LYT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gqtm0fChI78T9LYT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gqtm0fChI78T9LYT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gqtm0fChI78T9LYT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gqtm0fChI78T9LYT .marker.cross{stroke:#333333;}#mermaid-svg-gqtm0fChI78T9LYT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gqtm0fChI78T9LYT p{margin:0;}#mermaid-svg-gqtm0fChI78T9LYT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gqtm0fChI78T9LYT .cluster-label text{fill:#333;}#mermaid-svg-gqtm0fChI78T9LYT .cluster-label span{color:#333;}#mermaid-svg-gqtm0fChI78T9LYT .cluster-label span p{background-color:transparent;}#mermaid-svg-gqtm0fChI78T9LYT .label text,#mermaid-svg-gqtm0fChI78T9LYT span{fill:#333;color:#333;}#mermaid-svg-gqtm0fChI78T9LYT .node rect,#mermaid-svg-gqtm0fChI78T9LYT .node circle,#mermaid-svg-gqtm0fChI78T9LYT .node ellipse,#mermaid-svg-gqtm0fChI78T9LYT .node polygon,#mermaid-svg-gqtm0fChI78T9LYT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gqtm0fChI78T9LYT .rough-node .label text,#mermaid-svg-gqtm0fChI78T9LYT .node .label text,#mermaid-svg-gqtm0fChI78T9LYT .image-shape .label,#mermaid-svg-gqtm0fChI78T9LYT .icon-shape .label{text-anchor:middle;}#mermaid-svg-gqtm0fChI78T9LYT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gqtm0fChI78T9LYT .rough-node .label,#mermaid-svg-gqtm0fChI78T9LYT .node .label,#mermaid-svg-gqtm0fChI78T9LYT .image-shape .label,#mermaid-svg-gqtm0fChI78T9LYT .icon-shape .label{text-align:center;}#mermaid-svg-gqtm0fChI78T9LYT .node.clickable{cursor:pointer;}#mermaid-svg-gqtm0fChI78T9LYT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gqtm0fChI78T9LYT .arrowheadPath{fill:#333333;}#mermaid-svg-gqtm0fChI78T9LYT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gqtm0fChI78T9LYT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gqtm0fChI78T9LYT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gqtm0fChI78T9LYT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gqtm0fChI78T9LYT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gqtm0fChI78T9LYT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gqtm0fChI78T9LYT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gqtm0fChI78T9LYT .cluster text{fill:#333;}#mermaid-svg-gqtm0fChI78T9LYT .cluster span{color:#333;}#mermaid-svg-gqtm0fChI78T9LYT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gqtm0fChI78T9LYT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gqtm0fChI78T9LYT rect.text{fill:none;stroke-width:0;}#mermaid-svg-gqtm0fChI78T9LYT .icon-shape,#mermaid-svg-gqtm0fChI78T9LYT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gqtm0fChI78T9LYT .icon-shape p,#mermaid-svg-gqtm0fChI78T9LYT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gqtm0fChI78T9LYT .icon-shape .label rect,#mermaid-svg-gqtm0fChI78T9LYT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gqtm0fChI78T9LYT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gqtm0fChI78T9LYT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gqtm0fChI78T9LYT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否



发现慢查询
使用 EXPLAIN 分析
是否走索引?
优化索引设计
扫描行数是否过多?
优化查询条件
考虑数据量是否过大
分库分表/读写分离

二、发现问题:定位慢查询

1. 开启慢查询日志
sql 复制代码
-- 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过1秒的记录

-- 查看慢查询日志
mysqldumpslow -s t -t 10 /var/lib/mysql/slow-query.log
2. 查看正在执行的慢查询
sql 复制代码
-- 查看当前正在执行的所有查询
SHOW PROCESSLIST;

-- 找出执行时间长的
SELECT * FROM information_schema.PROCESSLIST
WHERE TIME > 5 AND COMMAND != 'Sleep'
ORDER BY TIME DESC;

三、分析问题:使用 EXPLAIN

1. EXPLAIN 基本用法
sql 复制代码
EXPLAIN SELECT * FROM users WHERE name = '张三'\G

-- 输出关键字段
字段 说明 好的信号 坏的信号
type 访问类型 const/ref/range ALL(全表扫描)
possible_keys 可能用的索引 有候选 NULL
key 实际用的索引 有值 NULL
rows 扫描行数
Extra 额外信息 Using index Using filesort
2. 关注 Extra 字段
sql 复制代码
-- ✅ 好
Using index          -- 覆盖索引,不需要回表
Using index condition -- 索引下推

-- ⚠️ 需要优化
Using filesort       -- 需要额外排序
Using temporary      -- 用了临时表

四、解决问题:核心优化技巧

1. 索引优化
sql 复制代码
-- 为 WHERE 条件建索引
CREATE INDEX idx_name ON users(name);

-- 为 ORDER BY 建索引
CREATE INDEX idx_create_time ON orders(create_time);

-- 复合索引注意最左前缀
CREATE INDEX idx_name_age ON users(name, age);
2. 避免 SELECT *
sql 复制代码
-- ❌ 不好
SELECT * FROM users WHERE name = '张三';

-- ✅ 好(只查需要的字段)
SELECT id, name FROM users WHERE name = '张三';
3. 避免在索引列上使用函数
sql 复制代码
-- ❌ 无法使用索引
SELECT * FROM orders WHERE YEAR(create_time) = 2024;

-- ✅ 可以走索引
SELECT * FROM orders
WHERE create_time >= '2024-01-01'
AND create_time < '2025-01-01';
4. 分页优化
sql 复制代码
-- ❌ 深分页问题
SELECT * FROM orders ORDER BY id LIMIT 100000, 10;

-- ✅ 使用游标分页
SELECT * FROM orders
WHERE id > 100000
ORDER BY id
LIMIT 10;
5. JOIN 优化
sql 复制代码
-- 小表驱动大表
-- 为 JOIN 字段建索引
CREATE INDEX idx_user_id ON orders(user_id);

五、高级优化技巧

1. 使用覆盖索引
sql 复制代码
-- 创建包含所有查询字段的索引
CREATE INDEX idx_covering ON users(name, age, id);

-- 查询可以直接从索引获取数据
SELECT id, name, age FROM users WHERE name = '张三';
-- Extra: Using index
2. 合理使用 EXISTS 替代 IN
sql 复制代码
-- IN 在大数据量时可能慢
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);

-- EXISTS 可能更快
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM orders o
              WHERE o.user_id = u.id AND o.amount > 1000);
3. 批量操作优化
sql 复制代码
-- 批量插入
INSERT INTO users (name) VALUES
('张三'), ('李四'), ('王五');  -- 一次插入多条

-- 批量更新使用临时表
CREATE TEMPORARY TABLE temp_updates (
    id INT PRIMARY KEY,
    age INT
);

六、监控和验证

1. 查看索引使用情况
sql 复制代码
-- 查看索引使用次数
SELECT
    index_name,
    rows_selected,
    rows_inserted
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'db_name';

-- 查看从未使用的索引
SELECT * FROM sys.schema_unused_indexes;
2. 查看查询缓存命中率
sql 复制代码
SHOW STATUS LIKE 'Qcache%';
SHOW STATUS LIKE 'Handler_read%';

七、总结:SQL 调优 Checklist

  • 是否开启了慢查询日志?
  • 是否用 EXPLAIN 分析了问题 SQL?
  • WHERE 条件字段是否有索引?
  • ORDER BY 字段是否有索引?
  • 是否避免了 SELECT *?
  • 是否避免了在索引列上使用函数?
  • JOIN 字段是否有索引?
  • 是否小表驱动大表?
  • 分页是否过深?
  • 是否有冗余或未用的索引?

一句话理解 :SQL 调优就像医生看病,先查症状(慢查询日志),再诊断病因(EXPLAIN),最后对症下药(索引优化、SQL重写)。

相关推荐
鹿角片ljp1 小时前
Redis 深度复习:从入门到面试通关
数据库·redis·面试
Csvn2 小时前
📊 SQL 入门 Day 12: 窗口函数基础
后端·sql
Ming_studying2 小时前
Python + SQLite FTS5 构建本地文档全文搜索器:增量索引、中文检索与高亮
jvm·数据库·python·sqlite
云和恩墨2 小时前
从静态备份到极速恢复:zData S重构多元数据库时代的“第二存储”底座
数据库·重构
吴声子夜歌2 小时前
MongoDB 8.0——存储
数据库·mongodb
网教盟人才服务平台3 小时前
Redis Key集中过期引发的流量雪崩实战解析
数据库·redis·缓存
AI大模型-小华3 小时前
ChatGPT充值后Codex误改数据库怎么办?用迁移审查避免数据丢失
数据库·chatgpt·codex·chatgpt plus·chatgpt pro·chatgpt充值
吴声子夜歌3 小时前
MongoDB 8.0——索引
数据库·mongodb
影寂ldy3 小时前
WinForm 完整版分页查询(多条件搜索+页码切换+每页条数切换)
数据库