MySQL 中的自定义变量用法、场景与最容易踩的坑
作者:sg_knight
在 MySQL 中,**自定义变量(User-Defined Variables)**是一种非常“灵活”的机制。
它不需要提前声明,可以在 SQL 中直接赋值、直接使用,因此在写复杂 SQL、做临时计算时经常能看到它的身影。
但同时,它也是 MySQL 里最容易被误用的特性之一。
本文从实际使用角度,系统讲清楚:
它是什么、怎么用、适合干什么、不适合干什么。
一、什么是 MySQL 自定义变量
MySQL 自定义变量是指以 @ 开头的变量,例如:
@count @total_price @row_num
它的核心特征有三点:
- 无需声明,直接使用
- 作用域是当前会话(session)
- 主要用于 SQL 执行过程中的临时存储
只要当前连接不断开,这个变量就一直存在。
二、自定义变量的基本用法
1. 变量赋值
常见的赋值方式有两种。
方式一:使用 SET
SET @a = 10; SET @b := 20;
方式二:在 SELECT 中赋值
SELECT @a := 10;
=和:=在赋值场景下都能用,但在复杂 SQL 中,推荐使用:=,可读性更好,也更安全。
2. 使用变量
变量赋值后,可以直接使用:
SELECT @a + @b;
也可以在查询中混合使用:
SELECT
id,
price,
@total := @total + price AS running_total
FROM orders,
(SELECT @total := 0) t;
三、自定义变量的典型使用场景
1. 计算累计值(运行总和)
这是最经典的用法之一:
SELECT
id,
amount,
@sum := @sum + amount AS total_amount
FROM payments,
(SELECT @sum := 0) s;
用于报表、统计、导出数据时非常方便。
2. 模拟行号(MySQL 8 之前)
在 MySQL 8.0 之前,没有 ROW_NUMBER(),很多人用自定义变量模拟:
SELECT
@rownum := @rownum + 1 AS row_num,
name
FROM users,
(SELECT @rownum := 0) r;
3. 复杂条件的中间状态保存
例如在一条 SQL 中保存上一次的值:
SELECT id, score, @prev := score AS prev_score FROM scores ORDER BY id;
四、自定义变量最容易踩的坑
这是重点。
1. 执行顺序不保证
MySQL 不保证 SELECT 中表达式的计算顺序。
例如:
SELECT @a := @a + 1, @a FROM table;
你不能假设左边一定先执行。
官方文档明确说明:
不要依赖用户变量在同一 SELECT 中的计算顺序
2. 在 WHERE / ORDER BY 中使用不安全
SELECT * FROM users WHERE score > (@avg := @avg + 1);
这种写法极不可靠,不同执行计划可能结果不同。
3. 并发场景下容易被误解
自定义变量是 会话级别 的,不是全局的。
- 不同连接之间 互不影响
- 但同一个连接里,多条 SQL 会共用
很多新手会误以为它是“全局变量”,这是错的。
4. 可读性和可维护性差
复杂 SQL 中大量使用 @变量:
- 后期几乎无法维护
- 新人很难理解
- 调试成本极高
五、什么时候不该用自定义变量
以下场景,强烈不推荐:
- 业务核心逻辑
- 更新、删除等写操作依赖变量顺序
- 高并发、强一致性要求
- 可以用窗口函数、子查询、CTE 解决的场景(MySQL 8+)
六、替代方案建议
如果你使用的是 MySQL 8.0+,优先考虑:
ROW_NUMBER()SUM() OVER (...)LAG / LEAD- CTE(WITH 语句)
这些都是语义清晰、结果可控的正规方案。
七、总结一句话
MySQL 自定义变量是“应急工具”,不是“长期方案”。
- 写报表、一次性 SQL:可以用
- 写核心业务、长期维护代码:尽量别用
如果你发现一条 SQL 里出现了 5 个以上的 @变量,
那大概率说明:设计该重构了。
到此这篇关于MySQL 中的自定义变量详解(用法、场景与坑)的文章就介绍到这了,更多相关mysql自定义变量内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
