前言
上篇我们介绍了数据写入、分组、内置函数相关的冷门语法,本篇聚焦性能优化、并发控制、动态字段、SQL 调试四大进阶方向。这些语法日常使用频率不高,但在 SQL 调优、并发场景、复杂计算、问题排查时能起到关键作用,是中高级后端开发必备知识点。
一、虚拟列(VIRTUAL / STORED)动态计算字段
MySQL 5.7+ 支持生成列(虚拟列) ,字段值由其他字段计算得出,无需 Java 代码手动计算,还支持建立索引,兼顾便捷性与查询性能。分为两种类型:
VIRTUAL(默认):不物理存储数据,查询时实时计算,不占用磁盘空间;STORED:物理存储数据,写入 / 更新数据时计算,占用磁盘空间。
示例
sql
-- 订单明细表:单价 * 数量 自动计算总价
CREATE TABLE `order_item` (
id INT PRIMARY KEY AUTO_INCREMENT,
price DECIMAL(10,2) COMMENT '单价',
num INT COMMENT '数量',
-- 虚拟列:查询时自动计算,无物理存储
total_price DECIMAL(10,2) GENERATED ALWAYS AS (price * num) VIRTUAL
) COMMENT '订单明细';
-- 正常插入数据,无需赋值 total_price
INSERT INTO `order_item` (price, num) VALUES (99.9, 2);
-- 直接查询计算后的总价
SELECT * FROM `order_item`;
进阶:给虚拟列建索引
虚拟列支持索引,适合高频筛选计算后字段的场景:
sql
CREATE INDEX idx_total_price ON order_item(total_price);
适用场景
金额计算、比例换算、状态衍生字段、拼接字段;
避坑
虚拟列不支持手动 INSERT/UPDATE 赋值,数值完全依赖计算表达式。
二、索引干预:FORCE INDEX / IGNORE INDEX
MySQL 优化器有时会选错索引(例如小表走全表扫描、优先使用低效索引),这时可以手动干预索引选择,强制使用 / 忽略指定索引。
1. FORCE INDEX 强制使用索引
sql
-- 强制使用 idx_name 索引查询
SELECT * FROM `sys_user`
FORCE INDEX (idx_name)
WHERE name = '张三';
2. IGNORE INDEX 忽略指定索引
sql
-- 忽略 idx_age 索引,让数据库自行选择最优方案
SELECT * FROM `sys_user`
IGNORE INDEX (idx_age)
WHERE age > 20;
适用场景
SQL 调优、优化器索引选择异常、复杂联表查询索引错乱;
避坑
仅作为临时调优手段,不建议在业务代码中长期使用,优先通过优化 SQL、统计信息解决索引问题。
三、并发控制:SELECT ... FOR UPDATE 行级悲观锁
在事务中,使用 FOR UPDATE 可以对查询到的行加行级排他锁,防止多事务并发修改数据,实现简单的悲观锁控制。锁生效范围:当前事务未提交前,其他事务无法更新 / 删除该行,普通查询不受影响。
示例
sql
-- 开启事务
BEGIN;
-- 锁定 id=1 的行,其他事务阻塞更新操作
SELECT * FROM `sys_user` WHERE id = 1 FOR UPDATE;
-- 执行业务更新逻辑
UPDATE `sys_user` SET age = 30 WHERE id = 1;
-- 提交事务,锁释放
COMMIT;
适用场景
库存扣减、金额变动、订单状态修改等强并发写场景;
避坑
- 锁仅在事务内生效;
- 查询条件必须命中索引,否则会升级为表锁;
- 控制事务执行时长,避免长事务导致锁等待。
四、SQL 调试:EXPLAIN ANALYZE 真实执行计划
传统 EXPLAIN 仅为预估执行计划,数据是 MySQL 优化器推算结果。MySQL 8.0.18+ 推出 EXPLAIN ANALYZE,真实执行 SQL,返回实际耗时、扫描行数、循环次数,是 SQL 调优神器。
示例
sql
-- 真实执行SQL,输出详细运行指标
EXPLAIN ANALYZE
SELECT * FROM `sys_user` WHERE dept_id = 1;
关键字段解读
actual time:真实执行耗时;rows:实际扫描 / 返回行数;Table scan:全表扫描(优化重点)。
适用场景
慢 SQL 排查、索引验证、复杂联表 SQL 性能分析。
五、交互式语法:HELP 内置帮助命令
不用翻阅官方文档,直接在 MySQL 客户端内查询语法、函数、关键字的官方说明,临时查用法非常方便。
示例
sql
-- 查询 SELECT 语法说明
HELP SELECT;
-- 查询索引相关语法
HELP INDEX;
-- 查询日期格式化函数用法
HELP DATE_FORMAT;
适用场景
线上服务器临时查语法、函数用法、忘记参数时快速检索。
六、REPLACE INTO 覆盖写入
REPLACE INTO 是一种特殊的写入语法:当主键 / 唯一索引冲突时,先删除原有数据,再插入新数据,区别于 ON DUPLICATE KEY UPDATE 的原地更新。
示例
sql
-- id 为主键,重复数据会先删后插
REPLACE INTO `sys_user` (id, name, age) VALUES (1, '王五', 29);
和 ON DUPLICATE KEY UPDATE 区别
REPLACE INTO:删旧数据 + 插新数据,自增 ID 会变化、触发器会多次触发;ON DUPLICATE KEY UPDATE:原地更新字段,数据行不变。
避坑
谨慎使用在主业务表,删除操作会影响关联数据、日志、触发器。
适用场景
临时配置表、缓存数据覆盖、简单数据重置。
总结
本篇语法偏向进阶优化与并发控制,侧重点和上篇形成互补:
- 虚拟列:将计算逻辑下沉到数据库,简化代码;
- 索引干预:临时解决优化器选错索引的问题;
- 行锁:实现简单悲观锁,应对并发更新;
- 执行计划 + 帮助命令:提升问题排查、学习效率;
- REPLACE INTO:特殊场景的数据覆盖写入。