优先用EXISTS判断记录存在性,因其找到首行即终止扫描,避免COUNT(1)全量计数带来的性能损耗;空值判断必须显式使用IS NULL或IS NOT NULL,不可用= ''或= NULL。

直接结论:优先用 IF + EXISTS 判断记录存在性,避免 COUNT(1);空值判断必须显式写 IS NULL 或 IS NOT NULL,不能用 = '' 或 = NULL。
为什么不用 COUNT(1) 做存在性判断
常见错误是写 IF (SELECT COUNT(1) FROM t WHERE id = @id) > 0 —— 这会强制全表扫描计数,哪怕只查一条记录也得算完全部匹配行。而 EXISTS 遇到第一条匹配就终止,性能差距可能达百倍。
-
EXISTS只关心“有没有”,不关心“有几个”,执行计划通常走索引查找(Seek) -
COUNT(1)必须统计全部匹配结果,容易触发索引扫描(Scan)甚至临时表 - 当表数据量大、条件选择性差时,
COUNT可能锁更久、阻塞更严重
NULL 和空字符串的判断必须分开处理
输入参数 @id 是 INT 类型却写 IF @id = '',SQL Server 会隐式转成 0,Oracle 报错,MySQL 可能静默失败。更糟的是,NULL 永远不等于任何值,包括它自己。
- 判断是否传了有效值:
IF @id IS NOT NULL AND @id 0(对数字) - 判断字符串参数是否为空:
IF LEN(ISNULL(@name, '')) > 0,而不是@name != '' - 混合场景下,明确区分意图:是“没传”(
NULL),还是“传了但为空”('')?两者语义不同,不能合并处理
动态 SQL 中拼接条件的坑
像 SET @sql = @sql + ' AND stud_id = ' + @id 这种写法,看似省事,实则埋雷:参数未转义、类型不匹配、SQL 注入风险、空值导致整个语句拼坏。
- 数字参数必须用
CONVERT(VARCHAR, @id)转换,不能直接拼接 - 字符串参数必须加单引号且转义单引号:
REPLACE(@name, '''', '''''') - 更安全的做法是用
sp_executesql配合参数化:EXEC sp_executesql @sql, N'@id INT', @id = @id - 如果只是简单条件分支,优先用静态 SQL +
IF分开写,比拼接更易读、更易调试
事务与错误处理别依赖手工 TRY...CATCH
在 SQL Server 中,SET XACT_ABORT ON 比层层套 TRY...CATCH 更可靠——它让任意运行时错误(包括约束冲突、死锁)自动回滚整个事务,避免部分成功、状态不一致。
- 开头加一句
SET XACT_ABORT ON,比每个INSERT/UPDATE前都包TRY简洁得多 -
TRY...CATCH适合需要捕获错误码、记录日志或做补偿操作的场景,不是默认选项 - 注意:MySQL 不支持
TRY...CATCH,要用DECLARE HANDLER,且仅限特定错误类型
真正难的不是写对一个 IF,而是想清楚“这个条件到底代表什么业务含义”——是参数缺失?是数据不存在?还是业务规则不满足?把语义理清了,SQL 才不会变成一堆修补补丁的胶水代码。

















