代码之家  ›  专栏  ›  技术社区  ›  t_warsop

为什么COALESCE要执行两次子查询?

  •  0
  • t_warsop  · 技术社区  · 7 年前

    我目前正在学习ISNULL和COALESCE之间的区别,我遇到一个声明说:

    COALESCE((<subquery), 0)
    

    转换为(根据SQL标准):

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

    我的问题是:为什么子查询要执行两次?这似乎效率低下。

    0 回复  |  直到 7 年前
        1
  •  1
  •   Gordon Linoff    7 年前

    ISNULL() 与SQL Server关联,所以这个问题似乎与SQL Server有关。正如评论中指出的,SQL Server会运行两次子查询。

    顺便说一句,这可能是决定性的——不仅仅是子查询。请考虑以下表达式:

    select coalesce(case when rand(checksum(newid())) < 0.5 then 'a' end, 'b')
    

    它可以返回一个 NULL 价值——尽管 COALESCE() ,因为第一个表达式计算了两次。为了好玩,您可以运行以下查询:

    select v.n, coalesce(case when rand(checksum(newid())) < 0.5 then 'a' end, 'b')
    from (values (1), (2), (3), (4), (5), (6), (7), (8)) v(n);
    

    我可以推测SQL Server会以这种方式运行的几个原因。

    (1) 微软或Sybase(曾几何时)的一些人实际上认为这是正确的方法。

    (2) 有人认为“我们已经有了一个功能来实现这一点,所以 聚结 应该有点不同。”即使这个“小差异”让它看起来像是坏了。

    (3) SQL Server不会通过只运行一次来优化子查询(据我所知)。因此,特别是对于子查询,我们的想法可能是:“我们将在以后的一轮优化中解决这个问题”。

    这都是猜测(因此也是观点)。我想回答这个问题,因为这不仅会影响子查询。