查询中重复出现的函数运算是执行多次还是一次?

hywink 2019-10-14 03:58:27
比如: select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

这里面sum(amt)和sum(qtt)都出现了两次, Sql Server在实际查询的时候是无脑的计算两次还是能优化到只计算一次?

希望提供答案的能说明依据或者证据, 多谢了.
...全文
259 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
二月十六 版主 2019-10-15
  • 打赏
  • 举报
回复
引用 7 楼 hywink 的回复:
[quote=引用 6 楼 hywink 的回复:] [quote=引用 1 楼 二月十六 的回复:] 以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
 select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname
看一下StmtText字段的内容,里边计算的sum定义应该只有一次
我进一步测试了一下, 对于聚合函数来说, 聚合是分在两步里面完成的, 一次流聚合, 在里面定义表达式, 一次标量计算重用了刚刚的表达式. 但是对于非聚合操作, 比如这个:
select len(amt),len(amt),* from TestCnt
  |--Compute Scalar(DEFINE:([Expr1004]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0)), [Expr1005]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))))
比如这个:
select len(amt)+2,len(amt)+1,* from TestCnt
  |--Compute Scalar(DEFINE:([Expr1004]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))+(2), [Expr1005]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))+(1)))
同样的函数都是在标量计算这一步里面调用的, 从这个结果里分析这么是调用了两次.[/quote] 再进一步, 查询列表中和选择条件中的相同的函数也是分别在不同步骤中执行的, 同样是执行两次.[/quote] 嗯以前我也没注意过这块的东西
hywink 2019-10-15
  • 打赏
  • 举报
回复
引用 6 楼 hywink 的回复:
[quote=引用 1 楼 二月十六 的回复:]
以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

看一下StmtText字段的内容,里边计算的sum定义应该只有一次

我进一步测试了一下, 对于聚合函数来说, 聚合是分在两步里面完成的, 一次流聚合, 在里面定义表达式, 一次标量计算重用了刚刚的表达式.

但是对于非聚合操作, 比如这个:
select len(amt),len(amt),* from TestCnt
|--Compute Scalar(DEFINE:([Expr1004]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0)), [Expr1005]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))))

比如这个:
select len(amt)+2,len(amt)+1,* from TestCnt
|--Compute Scalar(DEFINE:([Expr1004]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))+(2), [Expr1005]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))+(1)))

同样的函数都是在标量计算这一步里面调用的, 从这个结果里分析这么是调用了两次.[/quote]

再进一步, 查询列表中和选择条件中的相同的函数也是分别在不同步骤中执行的, 同样是执行两次.
hywink 2019-10-15
  • 打赏
  • 举报
回复
引用 1 楼 二月十六 的回复:
以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

看一下StmtText字段的内容,里边计算的sum定义应该只有一次

我进一步测试了一下, 对于聚合函数来说, 聚合是分在两步里面完成的, 一次流聚合, 在里面定义表达式, 一次标量计算重用了刚刚的表达式.

但是对于非聚合操作, 比如这个:
select len(amt),len(amt),* from TestCnt
|--Compute Scalar(DEFINE:([Expr1004]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0)), [Expr1005]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))))

比如这个:
select len(amt)+2,len(amt)+1,* from TestCnt
|--Compute Scalar(DEFINE:([Expr1004]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))+(2), [Expr1005]=len(CONVERT_IMPLICIT(varchar(12),[testdb].[dbo].[TestCnt].[amt],0))+(1)))

同样的函数都是在标量计算这一步里面调用的, 从这个结果里分析这么是调用了两次.
二月十六 版主 2019-10-14
  • 打赏
  • 举报
回复
引用 3 楼 hywink 的回复:
[quote=引用 1 楼 二月十六 的回复:]
以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

看一下StmtText字段的内容,里边计算的sum定义应该只有一次


这个查询结果里面体现了更多的执行计划的逻辑, 比界面上的执行计划里面显示出来的可是多的多.

这个具体的问题点还在其次, 多谢你让我知道了还可以这么看执行计划.[/quote]客气了,共同学习
hywink 2019-10-14
  • 打赏
  • 举报
回复
引用 1 楼 二月十六 的回复:
以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

看一下StmtText字段的内容,里边计算的sum定义应该只有一次


这个查询结果里面体现了更多的执行计划的逻辑, 比界面上的执行计划里面显示出来的可是多的多.

这个具体的问题点还在其次, 多谢你让我知道了还可以这么看执行计划.
hywink 2019-10-14
  • 打赏
  • 举报
回复
引用 1 楼 二月十六 的回复:
以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

看一下StmtText字段的内容,里边计算的sum定义应该只有一次


select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from dbo.TestCnt
|--Compute Scalar(DEFINE:([Expr1006]=[Expr1004]/[Expr1005]))
|--Compute Scalar(DEFINE:([Expr1004]=CASE WHEN [Expr1007]=(0) THEN NULL ELSE [Expr1008] END, [Expr1005]=CASE WHEN [Expr1009]=(0) THEN NULL ELSE [Expr1010] END))
|--Stream Aggregate(DEFINE:([Expr1007]=COUNT_BIG([testdb].[dbo].[TestCnt].[amt]), [Expr1008]=SUM([testdb].[dbo].[TestCnt].[amt]), [Expr1009]=COUNT_BIG([testdb].[dbo].[TestCnt].[qtt]), [Expr1010]=SUM([testdb].[dbo].[TestCnt].[qtt])))
|--Table Scan(OBJECT:([testdb].[dbo].[TestCnt]))


真是太感谢了, 写了这么多年SQL语句了, 才知道还有profile这个东西, 从这个结果上看是只执行一次.

帖子先放在这里, 让别人也看一看, 等沉下去我再结贴.
二月十六 版主 2019-10-14
  • 打赏
  • 举报
回复
以前没考虑过这个问题,不过我觉得应该只计算一次,楼主可以看看执行计划表
set statistics profile ON
select amt=sum(amt), qtt=sum(qtt), prc=sum(amt)/sum(qtt) from tbname

看一下StmtText字段的内容,里边计算的sum定义应该只有一次

34,576

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧