我们在SQL Server中遇到了一个有趣的问题。考虑以下repro示例:
CREATE TABLE #test (s_guid uniqueidentifier PRIMARY KEY);
INSERT INTO #test (s_guid) VALUES ('7E28EFF8-A80A-45E4-BFE0-C13989D69618');
SELECT s_guid FROM #test
WHERE s_guid = '7E28EFF8-A80A-45E4-BFE0-C13989D69618'
AND s_guid <> NEWID();
DROP TABLE #test;
请暂时忘记这种s_guid <> NEWID()
情况似乎毫无用处-这只是一个最小的复制示例。由于NEWID()
匹配某个给定常数的可能性非常小,因此每次都应将其评估为TRUE。
但事实并非如此。运行此查询通常返回1行,但有时(非常频繁,在10中超过1次)返回0行。我已经在系统上使用SQL Server 2008对其进行了复制,您可以使用上面链接的小提琴(SQL Server 2014)在线对其进行复制。
查看执行计划可以发现查询分析器显然将条件分为s_guid < NEWID() OR s_guid > NEWID()
:
...这完全解释了为什么有时会失败(如果第一个生成的ID小于给定ID,而第二个ID大于给定ID)。
即使其中一个表达式不是确定性的,也允许SQL Server将其评估A <> B
为A < B OR A > B
,吗?如果是,请在哪里记录?还是我们发现了错误?
有趣的是,AND NOT (s_guid = NEWID())
产生相同的执行计划(和相同的随机结果)。
当开发人员想要有选择地排除特定行并使用以下代码时,我们发现了此问题:
s_guid <> ISNULL(@someParameter, NEWID())
作为以下内容的“快捷方式”:
(@someParameter IS NULL OR s_guid <> @someParameter)
我正在寻找文档和/或错误确认。该代码并不十分相关,因此不需要解决方法。