我正在探索扩展事件查询跟踪,并对以下几个奇怪的查询有疑问:
示例 1:
select top 10 * from ( SELECT [id] ,[date] ,[ordnum] ,
[customer] ,[amt] ,[gm pc] FROM [DbName].[dbo].[tblSales] ) as [_]
where [date]>='2022-01-01T00:00:00.000'
示例 2:
select [_].[id], [_].[date], [_].[ordnum], [_].[customer], [_].[amt],
[_].[gm pc]
from ( SELECT [id] ,[date] ,[ordnum] , [customer] ,[amt] ,[gm pc]
FROM [DbName].[dbo].[tblSales] ) as [_] where [_].[date] >=
convert(datetime2, '2020-01-01 00:00:00')
and [_].[date] < convert(datetime2, '2021-01-01 00:00:00')
所以在子查询中它选择所有行。然后在外部查询中应用 where 条件。
如果它确实是这样工作的,那么这意味着子查询将进行全表扫描,然后将 where 子句应用于结果。或者这个查询是否得到优化,以便直接在表上应用 where 子句?
SQL 文本表达了所需的逻辑结果。SQL Server 的基于成本的优化器找到了一种有效的物理方法来实现该逻辑要求。当然,结果保证与 SQL 指定的结果相同(对于所有可能的数据值)。
优化器所做的基本事情之一是将过滤条件(谓词)尽可能向下推(朝向执行计划的叶子)。
因此,是的,出于所有实际目的,像您这样的示例“保证”不会按字面意思执行完整扫描后跟过滤器。过滤条件通常会作为扫描的一部分进行评估,或者更好的是作为索引范围搜索是否有合适的索引可用。
您似乎仍然在考虑执行计划,就好像每个运算符都执行到完成,然后再将结果行传递给下一个运算符。它不是那样工作的。有关详细信息,请参阅我的文章Iterators, Query Plans, and Why They Run Backwards。
虽然它有一些过程元素,但 SQL 的核心是声明式查询(通常表示为 sql 是一种声明式语言)。
这意味着 SQL 引擎决定如何满足您的请求。打个比方,你告诉它你想要一个汉堡包,但你没有告诉它什么时候翻转汉堡包或如何制作肉饼。
只要答案/动作正确,如何被认为是无关紧要的。当然,在其他条件相同的情况下,人们自然会更喜欢回答速度更快的引擎,因此该引擎接受查询,查看它对数据库的了解,并尝试选择综合考虑的最佳方法。
这包括诸如缓存结果、使用索引以及移动谓词之类的事情。
理论上每个操作都有一个定义的顺序,实际上,一切都是可选的,只要结果正确,就可以按任何顺序进行(或不进行)。
例如,如果您的 where 子句谓词说 not null,但该列本身不为 null,则可以完全删除该检查,在构建查询计划时满足它。或者左连接可能会变成内部连接,因为 where 子句表示连接列不为空或什至不是特定值。