假设一个与Stackoverflow类似的示例。您有一个内容项(问题或答案),您可以获取有关每个内容项的数据。每个数据都由以下数据表示:
然后您还要附加表示与单个内容项相关的用户交互的其他列:
这使我有可能指出用户与哪些内容项进行了互动以及该互动是什么。现在,内容项存储在Posts
表中,而操作(投票,评论)记录在单独的表PostActions
中,并带有列:
PostId
UserId
ActionType
(投票/投票,评论,垃圾邮件,关闭等)CreationDate
因此,对于每个项目,此表中有几行与每个项目相关。用户可能已对同一项目执行了多项操作。
我可以执行即。
select p.*, pa.ActionType
from Posts p
left join PostActions pa
on ((pa.PostId = p.PostId) and (pa.UserId = @UserId))
但这会导致与同一内容项相关的多行。为了将它们全部放在一个结果行中,我可以:
对每个操作单独使用left join PostActions
几次
select
p.*,
iif(paUp.CreationDate is null, 0, 1) as VotedUp,
iif(paDown.CreationDate isnull, 0, 1) as VotedDown,
...
from Posts p
left join PostActions paUp
on ((paUp.PostId = p.PostId) and (paUp.UserId = @UserId) and (paUp.ActionId = @UpVoteType))
left join PostActions paDown
on ((paUp.PostId = p.PostId) and (paUp.UserId = @UserId) and (paUp.ActionId = @DownVoteType))
...
但最终会有许多left join
到同一张桌子
我可以left join PostActions
并使用stuff
函数连接所有现有操作,然后在中间层解析
无论如何 - 即按PostActions.PostId
和PostActions.UserId
进行分组,然后从群组中获取该信息(如果可能的话,可以过滤具有多种不同条件的同一群组)。
使用pivot
或apply
获取我的数据
主要问题是哪种方法(上述或其他方法之一)在性能方面最佳?你会建议什么?
答案 0 :(得分:0)
我试验了一下,与我的上层可能性相关的是这个结果:
只有多个连接完全不可能。还必须实施分组,这会导致查询过于复杂且难以维护
需要上层后处理来解析连锁数据。 Haven没有实现它,因为它需要更多的上层代码更改,这些更改也会比数据层更加受限制。
我准备了一个CTE,它生成按内容项和用户分组的内容交互数据,并将结果连接到原始查询。运行良好,按预期工作。棘手的部分是过滤每组记录中的数据,只计算特定的交互(见下文)。
与#3类似的方法是使用pivot
关系运算符,我也实现了这一点,尽管预先准备好的数据也需要事先分组以获得每个项目一条记录
在#3和#4之间,我决定选择#3,因为它有更好的执行计划。
如#3(最终实现)中所述,为了使我的查询执行,我应该只进行一次分组,然后过滤每组记录中的数据以获取有关各个内容交互的信息。
因为我只需要指示特定用户是否在内容项上进行了交互,所有这些都返回布尔值(SQL bit
类型)。最好的部分是在count
聚合中使用函数,以便仅使用组内的特定记录。
with Interactions (Id, UpVoted, DownVoted)
as (
select
p.Id,
cast(count(iif(pa.ActionTypeId = @UpVoteType, 1, null)) as bit),
cast(count(iif(pa.ActionTypeId = @DownVoteType, 1, null)) as bit)
from PostActions pa
join Posts p
on (p.Id = pa.PostId)
where pa.UserId = @UserId
group by p.Id
)
select
...
isnull(i.UpVoted, 0) as UpVoted,
isnull(i.DownVoted, 0) as DownVoted
from Posts p
...
left join Interactions i
on (p.Id = i.Id)
where ...
order by ...
count
的好处是它只计算非空记录,因此我利用这一事实来过滤掉与内容项相关的同一组内的各个特定用户交互。
COUNT
是我的新爱。 :)