【问题标题】:Using ISNULL vs using COALESCE for checking a specific condition?使用 ISNULL 与使用 COALESCE 检查特定条件?
【发布时间】:2011-11-16 13:22:42
【问题描述】:

我知道可以将多个参数传递给COALESCE,但是当你想 只检查一个表达式以查看它是否不存在,您使用默认值还是使用ISNULL 是更好的做法?

两者之间有性能提升吗?

【问题讨论】:

标签: sql tsql coalesce isnull


【解决方案1】:

This problem reported on Microsoft Connect 揭示了COALESCEISNULL 之间的一些差异:

我们处理的早期部分将COALESCE( expression1, expression2 ) 重写为CASE WHEN expression1 IS NOT NULL THEN expression1 ELSE expression2 END。在[此示例]中:

COALESCE ( ( SELECT Nullable
             FROM Demo
             WHERE SomeCol = 1 ), 1 )

我们生成:

SELECT CASE
          WHEN (SELECT Nullable FROM Demo WHERE SomeCol = 1) IS NOT NULL
          THEN (SELECT Nullable FROM Demo WHERE SomeCol = 1)
          ELSE 1
       END

查询处理的后期不明白这两个子查询本来就是同一个表达式,所以执行了两次子查询……

一种解决方法,虽然我不想建议,但将COALESCE 更改为ISNULL,因为后者不会复制子查询。

【讨论】:

  • 快速提问,如果您有 3 个值,例如 coalesce(expression1, expression2, expression3, 1),其中这些“表达式”实际上是 select 语句,那么实际执行嵌套 isnull 语句是否有意义?即isnull(表达式1, isnull(表达式2, isnull(表达式3, 1)))
【解决方案2】:

我认为不是,但 COALESCE 符合 SQL '92 标准,并受到更多不同数据库的支持。如果您追求可移植性,请不要使用 ISNULL。

【讨论】:

  • @AaronAnodide MySQL 使用ifnull,sql server isnull
  • Oracle 对COALESCE 的替代方案是NVL。所以,COALESCE 是标准的观点是有效的,即使它的实现细节在数据库之间有所不同。
【解决方案3】:

COALESCE 可以有多个表达式,而ISNULL 只能检查一个表达式

COALESCE ( expression [ ,...n ] ) 

ISNULL ( check_expression , replacement_value )

【讨论】:

    【解决方案4】:

    值得一提的是,两者之间的类型处理也会有所不同(参见this related answer item (2))。

    假设一个查询尝试使用写空比较的快捷方式:

    select * from SomeTable
     where IsNull(SomeNullableBitField, -1) != IsNull(SomeOtherNullableBitField, -1);
    

    不同于

    select * from SomeTable
     where coalesce(SomeNullableBitField, -1) != coalesce(SomeOtherNullableBitField, -1);
    

    因为在第一种情况下,IsNull() 强制类型为位(因此 -1 转换为 true),而第二种情况会将两者都提升为 int。

    with input as 
    (
      select convert(bit, 1) as BitOn,      
             convert(bit, 0) as BitOff,
             convert(bit, null) as BitNull
    )
    select BitOn, 
           BitOff,
           BitNull,
           IsNull(BitOn, -1) IsNullBitOn,         -- true
           IsNull(BitOff, -1) IsNullBitOff,       -- false
           IsNull(BitNull, -1) IsNullBitNull,     -- true, converts the -1 to bit
           coalesce(BitOn, -1) CoalesceBitOn,     -- 1
           coalesce(BitOff, -1) CoalesceBitOff,   -- 0       
           coalesce(BitNull, -1) CoalesceBitNull  -- -1
      from input;
    

    关于问题本身有一个类似的评论/链接 (@Martin Smith)。

    【讨论】:

      【解决方案5】:

      我没有看到明确指出的一个主要事情是ISNULL 的输出类型类似于第一个表达式,但COALESCE 它返回最高优先级值的数据类型。

      DECLARE @X VARCHAR(3) = NULL
      DECLARE @Y VARCHAR(10) = '123456789'
      /* The datatype returned is similar to X, or the first expression*/
      SELECT ISNULL(@X, @Y) ---> Output is '123'
      /* The datatype returned is similar to Y, or to the value of highest precedence*/
      SELECT COALESCE(@X, @Y) ---> Output is '123456789'
      

      【讨论】:

      • 这不是第一个与第二个/第 N 个表达式的问题。见here:ISNULL uses the data type of the first parameter, COALESCE follows the CASE expression rules and returns the data type of value with the highest precedence.
      【解决方案6】:

      NULLCOALESCE 并不总是可以互换的。它应该知道它们的差异,以便知道什么时候使用一个比另一个更好:

      上表是 Itzik Ben-Gan 撰写的 Exam Ref 70-761 Querying Data with Transact-SQL 书中 ISNULLCOALESCE 之间的比较。


      1. 支持的参数数量 - 2 用于 ISNULL 与使用 COALESCE 时的 >2
      2. ISNULL 是专有的 T-SQL 功能,COALESCE 是 ISO/ANSI SQL 标准
      3. 结果的数据类型很重要。阅读上表中的注释后,检查以下情况:

        DECLARE @x VARCHAR(3)  = NULL
               ,@y VARCHAR(10) = '1234567890';
        
        SELECT ISNULL(@x, @y) AS [ISNULL], COALESCE(@x, @y) AS [COALESCE];
        

        ISNULL 正在获取第一个参数的数据类型,因为它不是 NULL 文字。它是VARCHAR(3),是结果,第二个参数数据 被切割以匹配它。如果最高优先级为 COALESCE,则数据类型为 用过。

        DECLARE @x VARCHAR(8)  = '123x5'
               ,@y INT = 123;
        
        SELECT ISNULL(@x, @y) AS [ISNULL];
        SELECT COALESCE(@x, @y) AS [COALESCE];
        

        ISNULL 正在返回第一个参数的数据类型,而在 COALESCE 我们收到错误,因为 INT 具有最高优先级,而 将第一个参数值转换为 INT 失败。

      4. 结果的可空性也很重要。例如:

        DECLARE @x VARCHAR(3) = NULL
               ,@y VARCHAR(3) = NULL;
        
        DROP TABLE IF EXISTS [dbo].[DataSource01];
        
        SELECT ISNULL(10, 20) AS [C1]
              ,ISNULL(@x, 'text') AS [C2]
              ,ISNULL(@x, @y) AS [C3]
        INTO [dbo].[DataSource01];
        
        DROP TABLE IF EXISTS [dbo].[DataSource02];
        
        SELECT COALESCE(10, 20) AS [C1]
              ,COALESCE(@x, 'text') AS [C2]
              ,COALESCE(@x, @y) AS [C3]
        INTO [dbo].[DataSource02];
        

        让我们检查每一列的Nullable 属性:

        使用COALESCE,我们将列的NOT NULL 属性设置为Yes,仅 当所有输入都不能为空时。

      5. 根据 SQL 标准,COALESCE 表达式被翻译为:

        CASE WHEN (<subquery>) IS NOT NULL THEN (<subquery>) ELSE 0 END
        

        如果WHEN子句中子查询的执行结果不是 NULL,SQL Server 在 THEN 子句中第二次执行它。 换句话说,在这种情况下,它会执行两次。只有当 WHEN 子句中的执行结果为 NULL,SQL Server 不 再次执行子查询,而不是返回 ELSE 表达式。所以 使用子查询时,ISNULL 函数有一个性能 优势。

      【讨论】:

        【解决方案7】:

        这个解释清楚地说明了 coalesce 与 isnull

        SQL 中的 COALESCE 函数返回其参数中的第一个非 NULL 表达式。 COALESCE 的语法如下:

         COALESCE ("expression 1", "expressions 2", ...)
        

        与下面的CASE语句相同:

        SELECT CASE ("column_name")
          WHEN "expression 1 is not NULL" THEN "expression 1"
          WHEN "expression 2 is not NULL" THEN "expression 2"
          ...
          [ELSE "NULL"]
          END
        FROM "table_name";
        

        在 SQL Server 中,ISNULL( ) 函数用于将 NULL 值替换为另一个值。

        select CountryName = ISNULL("columnname", 'INDIA') from Countries
        

        Coalesce 返回第一个非空表达式,其中 isnull() 用于将空值替换为我们想要的值。

        COALESCE 是 ANSI 标准的一部分,几乎可用于所有数据库。

        在 ISNULL 和 COALESCE 之间做出决定时,必须注意参数:

        1. COALESCE 根据数据类型优先级确定输出的类型,而对于 ISNULL,数据类型不受数据类型优先级的影响。
        2. 考虑以下 sql 语句

          DECLARE @c5 VARCHAR(5);
          SELECT 'COALESCE', COALESCE(@c5, 'longer name')
          UNION ALL
          SELECT 'ISNULL',   ISNULL(@c5,   'longer name');
          

        结果:

        COALESCE longer name
        ISNULL   longe
        

        这是因为 ISNULL 采用第一个参数的数据类型,而 COALESCE 检查所有元素并选择最合适的(在本例中为 VARCHAR(11))

        有关在 COALESCE 与 ISNULL 之间做出决定的更详细说明,请查看: https://www.mssqltips.com/sqlservertip/2689/deciding-between-coalesce-and-isnull-in-sql-server/

        【讨论】:

          【解决方案8】:

          在只有一个空条件的情况下,ISNULL 的开销会更少。不过,差异可能可以忽略不计。

          【讨论】:

          • 您是否支持ISNULL 的开销更少的说法?
          • @JoshuaDrake:有两个领域COALESCE 在互换使用时会引入更多开销。首先,ISNULL 处理固定数量的输入,其中COALESCE 被指定用于处理任意数量的输入。其次,COALESCE 配置为返回具有最高数据类型优先级的表达式的数据类型,而ISNULL 返回与check_expression 相同的类型。正如我上面所说,在 SQL Server 的更高版本中,差异可能可以忽略不计,但严格来说仍然存在开销。
          【解决方案9】:

          在 COALESCE 中可以使用多个表达式,它会返回非空值并且首先出现的值...例如

          DECLARE @Value1 INT, @Value2 INT, @Value3 INT, @Value4 INT
          SELECT @Value2 = 2, @Value4 = 4
          SELECT COALESCE(@Value1, @Value2, @Value3, @Value4)
          SELECT COALESCE(@Value1, @Value4, @Value3, @Value2)
          

          如果表达式为空,则在 ISNULL 中将返回提供的第二个参数,当然您只能检查一个表达式...

          所以如果要检查多个表达式并首先选择其中不为null,然后使用coalesce,否则使用ISNULL

          【讨论】:

          • OP 表示他们知道 COALESCE 处理多个参数的能力,问题是关于只有两个参数的具体情况。
          • @JoshuaDrake 请阅读完整的答案...我阅读了问题,我要求您完整阅读我的答案...很容易忽略一些观点并投反对票
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-12
          • 1970-01-01
          • 2012-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多