我有简单的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。
为什么在第一种情况下虽然不使用读取字段?
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
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
要获得带有两个分支的计划,该分支带有带有启动谓词的过滤器,因此在运行时仅执行相关的分支。