开发者社区 问答 正文

即使没有使用仍读取字段的SQL CASE

我有简单的SQL查询:

DECLARE @flag bit = 0;
SELECT TOP (100000) 
      [Id]
      CASE WHEN @flag=1 THEN [Description] END
FROM [dbo].[ReallyBigTable]

Description是一个非常大的字段,这里的变量标志只是字段的过滤器,在大多数情况下几乎是恒定的,但是比较类似查询的执行计划:

SELECT TOP (100000) 
      [Id]
FROM [dbo].[ReallyBigTable]

给我的信息是第一个查询中的Description实际上已被读取!它不会返回,但是磁盘上的I / O在那里。在第二种情况下,磁盘上没有太多I / O,并且查询执行非常快。两者之比约为25,因此第二个查询的I / O比第一个低25。

为什么在第一种情况下虽然不使用读取字段?

展开
收起
心有灵_夕 2019-12-25 21:43:38 898 分享 版权
1 条回答
写回答
取消 提交回答
  • SQL Server必须编译对参数的任何值均有效的执行计划@flag(在这种情况下,它是变量而不是参数,但适用于在甚至分配变量之前不知道其值的情况下编译语句的情况。考虑在内)。

    最简单的方法是在运行时撤回[Description]并评估CASE。这就是它的作用。

    如果您对此不满意,可以OPTION(RECOMPILE)在分配变量后添加以重新编译该语句。该计划不会被缓存,只需要对编译时已知的特定值有效。Description如果@flag=1不正确,这种“参数嵌入优化”可以简化引用。但这确实意味着每次执行都会重新编译。

    或者,您也可以将其分离为分别优化的不同语句-或将它们与UNION ALL和WHERE

    DECLARE @flag bit = 0;
    SELECT [Id],
           [Description]
    FROM [dbo].[ReallyBigTable]
    WHERE @flag=1
    UNION ALL
    SELECT [Id],
           NULL
    FROM [dbo].[ReallyBigTable]
    WHERE @flag = 0 OR @flag IS NULL
    
    

    要获得带有两个分支的计划,该分支带有带有启动谓词的过滤器,因此在运行时仅执行相关的分支。

    2019-12-25 21:44:01
    赞同 展开评论
问答分类:
SQL
问答地址: