当前位置: 首页 > news >正文

mysql查询优化

Mysql查询优化

🎯 一句话核心

查询优化= 让mysql少读数据+少做计算+走对索引

📊 优化前的准备工作

1.开启慢查询日志

-- 找到执行慢的SQL
SET GLOBAL slow_query_log = ON;
SET GONGLOBAL long_query_time = 1;  -- 超过1秒的记录

2.使用explain分析(重中之重)

EXPLAIN SELECT * FROM users WHERE age = 18;

explian结果怎么查看:

+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | users | ALL  | NULL          | NULL | NULL    | 10000| Using where|
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
  • 红色警报:
  • type = ALL全表扫描
  • key = NULL没走索引
  • rows = 10000扫描太多行
  • Extra = Using filesort文件排序

🔧 15个最实用的查询优化技巧

技巧1:只查询所需要的字段,不实用*

-- ❌ 差:查询所有字段
SELECT * FROM users WHERE age > 20;-- ✅ 好:只查需要的字段
SELECT id, name, age FROM users WHERE age > 20;-- 原因:减少IO、减少网络传输、可能用到覆盖索引

技巧2:避免在select中使用函数

-- ❌ 差:对索引字段使用函数
SELECT * FROM users WHERE YEAR(birthday) = 2024;-- ✅ 好:改成范围查询
SELECT * FROM users 
WHERE birthday >= '2024-01-01' AND birthday < '2025-01-01';-- 原因:函数会让索引失效

技巧3:避免隐式类型转换

-- ❌ 差:phone是varchar类型,传入数字
SELECT * FROM users WHERE phone = 13800138000;-- ✅ 好:传入字符串
SELECT * FROM users WHERE phone = '13800138000';-- 原因:类型转换会让索引失效

技巧4:like 查询%不要放前面

-- ❌ 差:%开头的LIKE
SELECT * FROM users WHERE name LIKE '%张%';-- ✅ 好:%放后面
SELECT * FROM users WHERE name LIKE '张%';-- ✅ 更好:使用全文索引
SELECT * FROM users WHERE MATCH(name) AGAINST('张');-- 原因:前导%导致索引失效

技巧5:不要使用on,改用union或者in

-- ❌ 差:OR可能导致索引失效
SELECT * FROM users WHERE age = 18 OR age = 20;-- ✅ 好:用IN
SELECT * FROM users WHERE age IN (18, 20);-- ✅ 更好:如果OR连接不同字段,用UNION
SELECT * FROM users WHERE age = 18
UNION
SELECT * FROM users WHERE name = '张三';-- 原因:OR可能让MySQL放弃索引

技巧6: 避免使用not in 、!=、<>

-- ❌ 差:负向查询不走索引
SELECT * FROM users WHERE age != 18;-- ✅ 好:改成正向查询
SELECT * FROM users WHERE age < 18 OR age > 18;-- ✅ 更好:分两次查
SELECT * FROM users WHERE age < 18
UNION
SELECT * FROM users WHERE age > 18;

技巧7:合理使用索引覆盖

-- 联合索引:idx_name_age (name, age)-- ✅ 好:查询字段都在索引里
SELECT name, age FROM users WHERE name = '张三';
-- Extra: Using index(完全覆盖)-- ❌ 差:需要回表查询
SELECT name, age, address FROM users WHERE name = '张三';
-- Extra: NULL(需要回表)

技巧8:分页优化(延迟关联)

-- ❌ 差:大偏移量分页
SELECT * FROM users ORDER BY id LIMIT 100000, 10;-- ✅ 好:先查ID,再关联
SELECT * FROM users 
INNER JOIN (SELECT id FROM users ORDER BY id LIMIT 100000, 10
) AS tmp ON users.id = tmp.id;-- ✅ 更好:记住上次位置(推荐)
SELECT * FROM users 
WHERE id > 100000 
ORDER BY id 
LIMIT 10;

技巧9:优化ORDER BY

-- ❌ 差:排序字段没索引
SELECT * FROM users ORDER BY age DESC;-- ✅ 好:排序字段建索引
ALTER TABLE users ADD INDEX idx_age(age);-- ✅ 更好:索引字段和排序顺序一致
ALTER TABLE users ADD INDEX idx_age_desc(age DESC);

技巧10:优化GROUP BY

-- ❌ 差:临时表分组
SELECT department, COUNT(*) 
FROM users 
GROUP BY department;-- ✅ 好:先过滤再分组
SELECT department, COUNT(*) 
FROM users 
WHERE status = 1 
GROUP BY department;-- ✅ 更好:分组字段建索引
ALTER TABLE users ADD INDEX idx_dept(department);

技巧11:避免使用DISTINCT

-- ❌ 差:DISTINCT耗时
SELECT DISTINCT department FROM users;-- ✅ 好:用GROUP BY代替
SELECT department FROM users GROUP BY department;-- ✅ 更好:如果只是去重,考虑缓存

技巧12:优化子查询

-- ❌ 差:相关子查询(每行执行一次)
SELECT * FROM users 
WHERE age > (SELECT AVG(age) FROM users u2 WHERE u2.department = users.department
);-- ✅ 好:改成JOIN
SELECT u.* FROM users u
INNER JOIN (SELECT department, AVG(age) as avg_ageFROM usersGROUP BY department
) tmp ON u.department = tmp.department
WHERE u.age > tmp.avg_age;

技巧13:优化UNION

-- ❌ 差:UNION会去重(耗时)
SELECT name FROM users_2023
UNION
SELECT name FROM users_2024;-- ✅ 好:不需要去重用UNION ALL
SELECT name FROM users_2023
UNION ALL
SELECT name FROM users_2024;-- 原因:UNION会做DISTINCT去重,UNION ALL直接合并

技巧14:大批量插入优化

-- ❌ 差:循环单条插入
INSERT INTO users VALUES (1, '张三');
INSERT INTO users VALUES (2, '李四');
-- ... 10000次-- ✅ 好:批量插入
INSERT INTO users VALUES 
(1, '张三'),
(2, '李四'),
-- ... 一次插入1000条
(1000, '王五');-- ✅ 更好:事务包裹
START TRANSACTION;
INSERT INTO users VALUES ... (1000条);
INSERT INTO users VALUES ... (1000条);
COMMIT;

技巧15:COUNT优化

-- ❌ 差:COUNT(列名)会判空
SELECT COUNT(age) FROM users;-- ✅ 好:COUNT(*)最快
SELECT COUNT(*) FROM users;-- ❌ 差:频繁COUNT大表
SELECT COUNT(*) FROM orders;-- ✅ 好:使用缓存或汇总表
-- Redis缓存总数,或维护统计表

📈 实战案例优化

案例1:查询2024年注册的VIP用户

-- 原始SQL(执行3秒)
SELECT * FROM users 
WHERE YEAR(reg_time) = 2024 
AND vip_level > 3 
ORDER BY last_login DESC;-- 优化后(0.1秒)
-- 1. 建复合索引
ALTER TABLE users ADD INDEX idx_reg_vip_login (reg_time, vip_level, last_login
);-- 2. 改写SQL
SELECT * FROM users 
WHERE reg_time >= '2024-01-01' 
AND reg_time < '2025-01-01'
AND vip_level > 3
ORDER BY last_login DESC;

案例2:分页查询商品评论

-- 原始SQL(执行5秒)
SELECT * FROM comments 
WHERE product_id = 100 
ORDER BY create_time DESC 
LIMIT 100000, 20;-- 优化后(0.05秒)
-- 1. 建索引
ALTER TABLE comments ADD INDEX idx_product_time (product_id, create_time
);-- 2. 记录上次位置
SELECT * FROM comments 
WHERE product_id = 100 
AND create_time < '2024-01-01 00:00:00'  -- 上次最后时间
ORDER BY create_time DESC 
LIMIT 20;

⚠️ 最易犯的5个错误

错误写法 问题 正确写法
WHERE name = 123 类型转换,索引失效 WHERE name = '123'
WHERE age + 1 = 20 索引列运算 WHERE age = 19
WHERE name LIKE '%张' 前导% WHERE name LIKE '张%'
WHERE age IS NULL 索引效率低 WHERE age = 0(设置默认值)
ORDER BY RAND() 全表排序 WHERE id >= (RAND()*max_id) LIMIT 1

🎯 优化检查清单

执行任何查询前,问自己:

  • 是否用了SELECT *?
  • WHERE条件是否让索引失效?
  • EXPLAIN的type是不是ALL?
  • 有没有用上合适的索引?
  • 分页是不是深度分页?
  • 排序字段有索引吗?
  • 连接查询的ON条件有索引吗?
  • 子查询可以改JOIN吗?
  • 数据量大是否可以缓存?

📚 一句话总结

查询优化三板斧:

  1. EXPLAIN看问题 → 找出全表扫描、文件排序
  2. 建合适的索引 → 复合索引、覆盖索引
  3. 改写SQL → 避免函数、类型转换、前导%

记住:优化1条烂SQL,胜过加10台服务器! 🚀

最后,希望我写的这篇博客对大家进一步学习mysql有更深刻的体会

http://www.jsqmd.com/news/375533/

相关文章:

  • HTML 标签列表(字母排序)
  • CSS 颜色名详解
  • 男士洗面奶怎么选?告别油光黑头,选对不踩坑 - 品牌测评鉴赏家
  • 官宣!XiangJsonCraft 2.0 正式版上线,纯JSON驱动的前端框架来了
  • 实测精选|男士洗面奶选购指南痛点+推荐+避坑,新手零踩雷 - 品牌测评鉴赏家
  • 2026国内最新防霉胶TOP5推荐:服务深度覆盖江苏、山东、济南、云南等地,抗菌防霉/防水型/厨卫门窗专用防霉胶权威榜单,适配高端全屋定制需求 - 品牌推荐2026
  • 从冯诺依曼到操作系统:打通 Linux 底层核心逻辑深度解析:原理、实战与踩坑记录
  • 2026国内最新防霉胶厂商TOP5推荐:服务深度覆盖江苏、山东、济南、云南等地,抗菌防霉/防水型/厨卫门窗专用防霉胶厂家权威榜单,适配高端全屋定制需求 - 品牌推荐2026
  • 基于遗传算法的车间调度附Matlab代码
  • LLC谐振变换器变频移相混合控制模型附Simulink仿真
  • 方达炬〖发明未知产业〗:建筑物空间勘探及其结构体开发业务
  • 自考避坑|4家靠谱学历提升机构实测推荐,在职党/零基础直接冲 - 品牌测评鉴赏家
  • FileZilla Server(服务端)
  • 数据库三范式
  • 2026春节档观影不踩雷:全类型影片汇总,适配带爸妈、约朋友、全家看全场景 - SFMEDIA
  • 2026国内最新玻璃胶生产商TOP5推荐:服务深度覆盖江苏、山东、济南、云南等地,高端定制/抗菌防霉/防水型等多场景适配,权威榜单助力精准选择 - 品牌推荐2026
  • 零基础学历提升必看!3家正规机构实测推荐,小白不踩雷 - 品牌测评鉴赏家
  • 2026口碑好的学历提升培训机构盘点!在职党/零基础直接抄作业,避坑不踩雷 - 品牌测评鉴赏家
  • 实用指南:华为云国际版 vs 阿里云国际版:东南亚市场选型指南
  • 2026春节档电影推荐指南:六部主力新片怎么选(全家人一起/带爸妈/朋友局) - SFMEDIA
  • 回收携程任我行礼品卡选对平台,京顺回收多赚的钱能再计划一次短途游 - 京顺回收
  • 上班族学历提升避坑|3家正规机构实测推荐,省时不花冤枉钱 - 品牌测评鉴赏家
  • Java高频面试题:Zookeeper的通知机制是什么?
  • 2026口碑封神!实测5家靠谱学历提升机构,上班族/零基础避坑抄作业 - 品牌测评鉴赏家
  • 数据编目在医疗大数据中的应用实践
  • 避坑指南|2026学历提升培训机构哪家好?博主实测整理,新手直接抄作业 - 品牌测评鉴赏家
  • 2026高性价比学历提升培训机构|实测避坑,上班族/零基础闭眼冲 - 品牌测评鉴赏家
  • 别再乱选!2026实测靠谱学历提升机构|上班族/零基础闭眼冲(无广纯干货) - 品牌测评鉴赏家
  • 2026执业药师冲刺押题班口碑红黑榜!3大宝藏机构+避坑指南,考生必看 - 品牌测评鉴赏家
  • 2026执业药师高性价比培训机构,备考党少花冤枉钱 - 品牌测评鉴赏家