IsNULL和Coalesce正确使用

Nil*_*ish 2 asp.net sql-server-2005 sql-server-2008

因为我们有两个选项来拦截来自数据库的空值...

  1. 一片空白
  2. 合并

以下是为上述两个函数编写查询的方法......

Select IsNull(Columnname, '') As validColumnValue From TableName

Select Coleasce(Columnname, '') As validColumnValue From TableName

查询 - 应该优先选择哪种情况以及为什么?

Aar*_*and 5

这已被哈希并重新散列.除了我在评论中指出的提示以及上面发布的@xQbert链接和解释之外,这里的请求是使用子查询对COALESCE与ISNULL的解释.让我们考虑这两个查询,这些查询在结果方面是相同的:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');
Run Code Online (Sandbox Code Playgroud)

(关于使用没有ORDER BY的TOP到/ dev/null/thanks的评论.)

在COALESCE案例中,逻辑实际上扩展为如下所示:

SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
    THEN (SELECT TOP (1) ...)
    ELSE N'foo'
END
Run Code Online (Sandbox Code Playgroud)

使用ISNULL,这不会发生.有一个内部优化似乎确保子查询只被评估一次.我不知道微软以外的人是否知道这种优化的确切方式,但如果你比较计划,你可以这样做.以下是COALESCE版本的计划:

在此输入图像描述

这是ISNULL版本的计划 - 请注意它是多么简单(并且扫描只发生一次):

在此输入图像描述

在COALESCE情况下,扫描发生两次.这意味着子查询被评估两次,即使它没有产生任何结果.如果添加一个WHERE子句使得子查询得0行,你会看到类似的差异 - 计划的形状可能会改变,但你仍然会看到一个双寻求+查找或扫描的COALESCE情况.这是一个略有不同的例子:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');
Run Code Online (Sandbox Code Playgroud)

这次是COALESCE版本的计划 - 再次你可以看到代表子查询的整个分支一再重复:

在此输入图像描述

再一个更简单的计划,大约一半的工作,使用ISNULL:

在此输入图像描述

您还可以在dba.se上查看此问题以获得更多讨论:

https://dba.stackexchange.com/questions/4274/performance-difference-for-coalesce-versus-isnull

我的建议就是这个(你可以在提示和上面的问题中看到我的原因):信任但要验证.我总是用COALESCE(因为它是ANSI标准,支持两个以上的参数,并没有对数据类型优先作为相当靠不住的东西),除非我知道我使用子查询的表达式之一(我不回想曾经做过这样的理论工作之外的事情)或者我遇到了一个真正的性能问题,只是想比较看看COALESCE和ISNULL是否有任何实质性的性能差异(在子查询案例之外,我还没有找到).由于我几乎总是使用COALESCE与类似数据类型的参数,我很少需要做任何测试,而不是回顾过去我曾经说过的内容(我也是xQbert指出的aspfaq文章的作者),7年前).