3

我在查询具有父/子关系行的表时遇到问题。在编写一个简化示例时,我意识到 stackexchange 模式非常相似。

所以想象一下,我正在通过 stackexchange 数据浏览器查询 stackoverflow 帖子表。我正在尝试获取所有帖子及其相关答案的子集。

有关示例查询,请参阅https://data.stackexchange.com/stackoverflow/query/121981/a-subset-of-questions-and-associated-answers

帖子的子集在视图中定义,该视图具有相当复杂和昂贵的查询计划。在下面的示例中,它已被简化为简单地选择前两行。

第一种方式,使用联合:

with ExpensiveView as (select top 2 ID from Posts order by ID)

select Posts.*
from ExpensiveView
left outer join Posts
  ON ExpensiveView.Id = Posts.Id 
  
union all

select Posts.*
from ExpensiveView
left outer join Posts
  ON ExpensiveView.Id = Posts.ParentId

我很想避免这种方式,因为ExpensiveView被评估了两次。对于上面的简化版本显然不是问题,但会导致更复杂的问题。

第二种方式,使用带有条件连接子句的单选:

with ExpensiveView as (select top 2 ID from Posts order by ID)

select Posts.*
from ExpensiveView
left outer join Posts
  ON ExpensiveView.Id = Posts.Id or ExpensiveView.Id = Posts.ParentId

这避免了ExpensiveView被评估两次,但会导致非常大的聚集索引扫描。它似乎正在扫描每个 ID 中的整个索引ExpensiveView(因此 2 * 14977623 = ~3000 万行)。这是非常缓慢的。

两个问题

为什么第二个查询中的条件连接会导致如此大的索引扫描?

ExpensiveView有什么方法可以在不被多次评估的情况下获得我正在寻找的结果?

4

1 回答 1

0

尝试这个

with
ExpensiveView as (select top 2 ID from Posts order by ID),
CTE_Posts as (
    select *, NP.Id as New_Post_ID
    from Posts as P
        outer apply (select P.Id union all select P.ParentId) as NP
)
select
    P.*
from ExpensiveView as E
    left outer join CTE_Posts as P on P.New_Post_ID = E.ID
于 2013-07-27T20:16:00.517 回答