为什么我必须使用这些层次结构查询强制排序/

Why do I have to Force Order with these hierarchy queries/

下面是我可能 运行 的查询示例,其中对于每个类别,我希望 NumberOfCourses 不仅代表该特定类别,还代表其下的所有子类别。我认为该查询相当不言自明。

select  c.CategoryID, courses.MarketID, count(distinct courses.CourseID) NumberOfCourses
from    Category c
        join CategoryHierarchy tch on tch.HierarchyKey like '%~' + cast(c.CategoryID as varchar) + '~%'
        join vLiveEvents courses on tch.CategoryID = courses.CategoryID
where   courses.MarketID is not null
group by c.CategoryHumanID, courses.MarketID

当我运行按原样执行时,可能需要将近两分钟,但是如果我添加提示Option (Force Order),则只需几秒钟即可运行。所以我的问题是我是不是做错了什么导致 SQL 制定了一个糟糕的计划,或者 SQL 引擎实际上并不擅长像这样优化层次结构连接?

我尝试包括 sql 计划,但它太长了,所以不会让我有那么多角色。如果有人能告诉我如何分享,我很乐意分享它。

编辑:我想可能不是每个人都知道这些层次结构是如何工作的。它们的层次结构键类似于 ~1234~5678~9123~,其中 1234 是 5678 的父级,5678 是 9123 的父级。通过对 CategoryID 进行类似比较,我可以在结果中包含所有子类别。

从SQL Server 2016+开始,引入了查询存储功能来监控性能。它提供了对查询计划选择和性能的洞察。

It also provides an option to force plan.

它不是跟踪或扩展事件的完全替代品,但随着它从一个版本发展到另一个版本,我们可能会在未来的版本中从 SQL 服务器获得一个功能齐全的查询存储。 Query Store的主要流程

  1. SQL 服务器现有组件通过使用查询存储管理器与查询存储交互。
  2. 查询存储管理器确定应使用哪个存储,然后将执行传递给该存储(计划或运行时统计或查询等待统计)
    • Plan Store - 保存执行计划信息
    • Runtime Stats Store - 保存执行统计信息
    • Query Wait Stats Store - 持久化等待统计信息。
  3. 计划、运行时统计和等待存储使用查询存储作为 SQL 服务器的扩展。

  1. 启用查询存储:查询存储在服务器上的数据库级别工作。

    • 默认情况下,新数据库的查询存储不活动。
    • 您不能为主数据库或 tempdb 数据库启用查询存储。
    • 可用的 DMV

      sys.database_query_store_options (Transact-SQL)

  2. 在查询存储中收集信息:我们使用查询存储 DMV(数据管理视图)从三个存储中收集所有可用信息。

注意: 查询等待统计存储仅在 SQL Server 2017+

中可用