我正在审查我继承的一些代码,我发现了这样的一行:
And isnull(IH.CustomerItemNumber, '') <> ''
我的前任中的哪一位似乎曾在大量的where子句或join子句中使用过。在我看来,这是一个不必要的函数调用,因此性能损失,因为NULL永远不会等于空字符串'',对吗?
具体来说,我从特定查询中的join子句中取出了这个,并且性能显着提高(从46-49秒到1-3之间)。
将其替换为AND IH.CustomerItemNumber <> ''
我的评估是否正确?这是多余的,缓慢的,可以删除?在什么情况下这段代码可能是有益的?
编辑:那么,NULL是否可以等于空字符串?
答案 0 :(得分:5)
这在语义上与:
相同And IH.CustomerItemNumber <> '' And IH.CustomerItemNumber Is Not Null
因此检查列是否为空且不是空字符串。可能很重要。
<强>更新强>
在这种情况下,因为我们正在寻找字符串文字(空字符串)的不相等,所以至少有三个语义正确的选项:
And IH.CustomerItemNumber <> ''
And IH.CustomerItemNumber <> '' And IH.CustomerItemNumber Is Not Null
And isnull(IH.CustomerItemNumber, '') <> ''
第一个将返回与其他两个相同的结果集,因为<> ''
将无法匹配null,无论ansi_nulls设置如何。
在开发系统的快速测试中,第一个和第二个都使用索引搜索。第一个非常轻微地在一些非常简化的测试中胜过第二个
。第三个,因为它添加了一个函数调用,可能不会像其他函数那样使用索引,所以这可能是最糟糕的选择。也就是说,在快速测试中,isnull能够使用索引扫描。进一步将Is Not Null
添加到第三个选择实际上加速了它并将其移动到索引搜索。去图(GO!GO!查询优化器!)。
与@Gordon一样,我也会多次选择第二个选项,因为它会更好地表达我对其他开发人员(或我自己)的意图,如果我们检查与另一个列的相等性,那么这将是一个更好的做法。 null(想想潜在的ansi_nulls)。
为了完整起见:
And nullif(IH.CustomerItemNumber, '') is not null
And case when IH.CustomerItemNumber = '' then null else IH.CustomerItemNumber end is not null
And case IH.CustomerItemNumber when '' then null else IH.CustomerItemNumber end is not null
在SQL Server中,所有解释方式都完全相同(据我所知)并执行与上面第三个选项相同的操作。
答案 1 :(得分:4)
代码存在的原因可能是因为应用程序的历史记录。也许在某个时间点,字段中允许NULL。然后,用空字符串替换它们。
代码效率低下的原因是由于连接的优化。 ISNULL()
及其ANSI标准等效COALESCE()
通常会增加查询处理的开销。 (似乎在某些版本的SQl Server中,COALESCE()
会对第一个参数进行两次计算,如果它是子查询则会出现问题。)
我的猜测是该字段有一个索引。当单独使用该字段时,SQL Server知道使用索引进行连接。在函数调用中包含索引时使用索引是不够智能的。正是连接优化会降低查询速度,而不是函数调用的开销。
就个人而言,如果性能相同,我更喜欢具有显式NULL检查的表单:
IH.CustomerItemNumber <> '' and IH.CustomerItemNumber is not null
明确关于NULL处理只能帮助您将来维护代码。
答案 2 :(得分:1)
您可以使用NULL检查:
And (IH.CustomerItemNumber IS NOT NULL) AND (IH.CustomerItemNumber <> '')
顺便说一句, ISNULL ( check_expression , replacement_value ) - 使用指定的替换值替换NULL。
在你的情况下,如果IH.CustomerItemNumber的值为null,那么它将被空值替换,然后将其与空字符串进行比较。
答案 3 :(得分:0)
因为NULL永远不会等于空字符串'',对吗?
NULL也永远不会不等于到空字符串......它既是同时又不是全部同时。它传达了一个你不确定的状态。