我正在编写一个正在执行的触发器
IF (@A <> @B)
...
但这不适用于@A或@B上的NULL值。它通常的方式是
IF (@A <> @B) OR (@A IS NOT NULL AND @B IS NULL) OR (@A IS NULL AND @B IS NOT NULL)
但这涉及最多9次比较而不是1次!
我能做到
SET ANSI_NULLS OFF
但显然不建议这样做(并且不推荐使用)。
那么最佳解决方案是什么?当它应该为1时,只需进行9次比较即可进行简单的不等式检查?触发器不是性能关键,但确实需要快速。批量加载时,这可能会大大减慢它的速度。
表演测试
以下是performance test的结果,它检查不等式一百万次,使得90%的时间值不相等,10%的时间每个值可能为空。
IF (@A <> @B) OR (@A IS NULL AND @B IS NOT NULL) OR (@A IS NOT NULL AND @B IS NULL)
结果:平均3848毫秒
IF (ISNULL(@A, 0) <> ISNULL(@B, 0))
结果:平均3942毫秒
IF (@A = @B) GOTO Equal ELSE IF @A IS NULL AND @B IS NULL GOTO Equal
结果:平均4140毫秒
IF EXISTS (SELECT @A EXCEPT SELECT @B)
结果:平均7795ms
时间并不重要,重要的是相对差异。显然,经典方法是最快的。可能的MSSQL内部针对此类检查进行了优化。
在MacBook Pro上运行测试(运行MSSQL 2008 Express的Vista VM中的Intel Core 2 Duo,2.4Ghz,8GB RAM)。
答案 0 :(得分:7)
ANSI SQL有IS DISTINCT FROM
但SQL Server中没有实现。它可以是simulated,不依赖于魔术常量,并且如果在列上使用则可以是sargable
IF EXISTS (SELECT @A EXCEPT SELECT @B)
PRINT 'Different'
答案 1 :(得分:2)
在我看来,这是检查可空性并提供默认值的最佳方法。
IF ( ISNULL(@A, 0) <> ISNULL(@B, 0) )
一般语法
ISNULL ( check_expression , replacement_value )
如果不是NULL,则返回check_expression的值; 否则,在隐式地返回replacement_value 如果类型不同,则转换为check_expression的类型。 如果replacement_value超过,则replacement_value可以被截断 check_expression。
答案 2 :(得分:2)
您可以执行以下操作
ISNULL(@A,'N') <> ISNULL(@B,'N')
答案 3 :(得分:1)
以下是performance test的结果,它检查不等式一百万次,使得90%的时间值不相等,10%的时间每个值可能为空。
IF (@A <> @B) OR (@A IS NULL AND @B IS NOT NULL) OR (@A IS NOT NULL AND @B IS NULL)
结果:平均3848毫秒
IF (ISNULL(@A, 0) <> ISNULL(@B, 0))
结果:平均3942毫秒
IF (@A = @B) GOTO Equal ELSE IF @A IS NULL AND @B IS NULL GOTO Equal
结果:平均4140毫秒
IF EXISTS (SELECT @A EXCEPT SELECT @B)
结果:平均7795ms
时间并不重要,重要的是相对差异。显然,经典方法是最快的。可能的MSSQL内部针对此类检查进行了优化。
在MacBook Pro上运行测试(运行MSSQL 2008 Express的Vista VM中的Intel Core 2 Duo,2.4Ghz,8GB RAM)。
答案 4 :(得分:0)
我知道很多人不会喜欢这个,但因为表现是一个重要的问题,我正在使用它(除非有人有充分的理由)
IF @A = @B GOTO Equal ELSE IF @A IS NULL AND @B IS NULL GOTO Equal
NotEqual:
PRINT 'Different'
Equal:
这要快得多,因为几乎总是@A和@B相等,只有1次比较。在少数情况下,当@ A和@B不相等时,需要进行1.5次平均比较才能确定不平等。
这是针对触发器中行更新的列级审核。比较@A和@B表示每个表的每次更新中每行中每列的“旧值”和“新值”。