别只会写 SELECT!这 10 个 MySQL 技巧太香了,效率直接翻倍

admin 2025-11-24 09:42 新闻动态 160

别只会写 SELECT!这 10 个 MySQL 技巧太香了,效率直接翻倍

**

作为每天和数据库打交道的程序员,我发现太多人还停留在 “SELECT * 走天下” 的阶段。明明一行 SQL 能搞定的事,偏要写十几行代码;明明能优化到毫秒级的查询,非要卡成 “龟速”……

今天掏家底分享 10 个实战派 MySQL 技巧,全是我踩过坑、验过证的干货。不管是做报表统计、处理重复数据,还是优化慢查询,学会了直接省出喝咖啡的时间!

一、JSON 字段:动态数据的 “免扩容” 方案

痛点:用户自定义配置、商品多规格这类动态字段,加字段嫌麻烦,存字符串又难解析?

技巧:MySQL 5.7 + 支持 JSON 类型,直接存键值对,灵活又好查!

-- 创建用户偏好表(JSON存动态配置)

CREATE TABLE user_preferences (

id INT PRIMARY KEY,

user_id INT,

preferences JSON -- 动态字段

) COMMENT '用户偏好表';

-- 插入数据

INSERT INTO user_preferences VALUES

(1, 1, '{"theme":"dark","fontSize":14,"notifications":true}'),

(2, 2, '{"theme":"light","fontSize":16,"notifications":false}');

-- 精准查“主题”配置(-> 符号提取值)

SELECT preferences->'$.theme' AS user_theme FROM user_preferences WHERE user_id=1;

-- 结果:"dark"

真香点:不用改表结构就能扩字段,还支持索引优化,比存字符串香 10 倍!

二、WITH ROLLUP:报表统计 “一键加总计”

痛点:统计各部门薪资,还要算全局总和,难道要查两次?

技巧:GROUP BY 加 WITH ROLLUP,一次查询出分组 + 总计。

-- 统计各部门人数、薪资及总计

SELECT

department AS '部门',

COUNT(*) AS '人数',

SUM(salary) AS '薪资总和'

FROM employees

GROUP BY department WITH ROLLUP;

-- 结果直接带总计行

-- 部门 人数 薪资总和

-- 技术部 3 50000

-- 市场部 2 25000

-- NULL 7 96000 -- 自动生成的总计

避坑提示:总计行的分组字段会显示 NULL,前端判断时注意处理。

三、CASE WHEN:多条件统计 “一行搞定”

痛点:统计活跃 / 非活跃用户、不同状态订单,要写多条 SQL?

技巧:CASE WHEN 做条件聚合,单条查询出所有维度。

-- 一次统计多种状态用户数

SELECT

SUM(CASE WHEN status='active' THEN 1 ELSE 0 END) AS '活跃用户',

SUM(CASE WHEN status='inactive' THEN 1 ELSE 0 END) AS '非活跃用户',

SUM(CASE WHEN create_time>='2025-01-01' THEN 1 ELSE 0 END) AS '新增用户'

FROM users;

-- 结果清晰直观

-- 活跃用户 非活跃用户 新增用户

-- 120 35 48

实战场景:做运营报表、数据看板必备,省去后端拼接数据的麻烦。

四、INSERT IGNORE:重复数据 “自动跳过”

痛点:批量导入数据,遇到主键冲突直接报错,整批都失败?

技巧:用 INSERT IGNORE,重复数据静默跳过,不影响其他数据。

-- 导入用户数据,已存在的id=1记录直接跳过

INSERT IGNORE INTO users (id, name, email) VALUES

(1, '张三', 'zhangsan@example.com'), -- 重复,跳过

(3, '王五', 'wangwu@example.com'); -- 新增,成功

适用场景:日志导入、历史数据迁移,不用先查后插,代码少一半。

五、ON DUPLICATE KEY UPDATE:“存在更新,不存在插入”

痛点:更新用户信息,要先查有没有这个用户,再决定插还是更?

技巧:用这个语句实现 “upsert”,一条 SQL 搞定两种逻辑。

-- 按id判断:有则更新,无则插入

INSERT INTO users (id, name, email) VALUES

(1, '张三', 'zhangsan_new@example.com'), -- 已存在,更新邮箱

(4, '赵六', 'zhaoliu@example.com') -- 不存在,插入

ON DUPLICATE KEY UPDATE

name = VALUES(name), -- 用新值更新

email = VALUES(email);

注意:必须有主键或唯一索引才能触发,否则会变成普通插入。

六、FIND_IN_SET:逗号分隔字段 “精准查询”

痛点:商品分类存成 “1,2,3”,想查含分类 1 的商品怎么搞?

技巧:别用 LIKE !FIND_IN_SET 专门处理集合查询。

-- 商品表:category_ids存逗号分隔的分类ID

SELECT * FROM products WHERE FIND_IN_SET('1', category_ids);

-- 正确匹配:category_ids为1、1,2、1,3的记录

-- 不会匹配:10、21(LIKE会误判)

避坑提示:虽然好用,但尽量少用逗号存集合,量大了建议拆成关联表。

七、GROUP_CONCAT:多行数据 “合并成字符串”

痛点:查部门员工列表,结果是多行,前端要循环拼接?

技巧:GROUP_CONCAT 直接合并,后端少写 10 行处理代码。

-- 按部门合并员工姓名(逗号分隔,按姓名排序)

SELECT

department AS '部门',

GROUP_CONCAT(name ORDER BY name SEPARATOR ', ') AS '员工列表'

FROM employees

GROUP BY department;

-- 结果直接能用

-- 部门 员工列表

-- 技术部 李四, 王五, 张三

-- 市场部 赵六, 钱七

小技巧:默认长度限制 1024,可通过 SET group_concat_max_len=102400 扩大。

八、EXISTS:子查询优化 “速度起飞”

痛点:用 IN 做子查询,数据量大时卡到超时?

技巧:换成 EXISTS,只判断 “是否存在”,效率提升 N 倍。

-- 低效:IN子查询(会全表扫描子查询结果)

SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE city='北京');

-- 高效:EXISTS(找到匹配就停止,不用查全部)

SELECT * FROM orders o

WHERE EXISTS (SELECT 1 FROM users u WHERE u.id=o.user_id AND u.city='北京');

原理:EXISTS 是 “短路判断”,只要子查询有结果就返回,大数据量下优势明显。

九、ROW_NUMBER ():分页排序 “不丢数据”

痛点:用 LIMIT 分页,遇到相同排序值(如相同薪资),翻页可能丢数据?

技巧:用窗口函数 ROW_NUMBER () 加唯一排序条件。

-- 按薪资降序分页,用id保证排序唯一

SELECT * FROM (

SELECT

*,

ROW_NUMBER() OVER (ORDER BY salary DESC, id ASC) AS rn

FROM employees

) t WHERE rn BETWEEN 11 AND 20;

实战场景:排行榜、分页列表,再也不怕数据重复或丢失。

十、EXPLAIN:慢查询 “一键诊断”

痛点:SQL 跑半天,不知道卡在哪?

技巧:在查询前加 EXPLAIN,瞬间看清执行计划。

-- 分析查询为什么慢

EXPLAIN SELECT * FROM orders WHERE user_id=123 AND create_time>='2025-01-01';

关键看这 2 列:

type:显示连接类型,出现 “ALL” 就是全表扫描,要加索引;

key:显示用到的索引,为 NULL 说明没走索引,赶紧优化。

附避坑清单:这些错误别再犯了!

禁用 SELECT * :浪费带宽,暴露敏感字段;

LIKE 别用前导 % :%北京 会让索引失效;

大分页不用 OFFSET :用 WHERE id > 1000 LIMIT 10 替代 LIMIT 1000,10;

事务别写太长 :避免长时间锁表影响并发。

以上 10 个技巧,每个都在实际项目中救过我的急。其实 MySQL 的强大远不止于此,关键是别停留在基础操作,多琢磨 “有没有更优解”。

你平时最常用哪个 MySQL 技巧?或者踩过什么 SQL 坑?欢迎在评论区交流,点赞过万再出进阶版!

上一篇:哈尔斯:上半年归母净利润9135.16万元,同比下降29%
下一篇:小米一款海外机型或取消赠送充电器 预计为K90海外版

热点文章

华人娱乐平台论坛