【问题标题】:Group by in a denormalized table在非规范化表中分组
【发布时间】:2021-01-13 21:00:23
【问题描述】:

我们有一个包含非规范化数据的表,其中存储事件,其中包括以下字段: 产品编号 |产品名称 |子类别 ID

它们直接相互依赖,因此对于特定的 productid,Productname 和 subcategoryid 可能只有一个值。 由于我们存储事件,因此我们有许多行将包含与上述三个字段相关的相同信息。

我们现在正在设计一个查询来获取唯一的 productid、productname 和 subcategoryid。 这些查询将返回相同的实体:

select ProductId from VisitEvents
group by ProductId

就像这个:

select productid, productname, subcategoryid from visitevents
group by productid, productname, subcategoryid

但是后者要慢几个数量级。 除了第一个查询中的分组之外,还有其他方法可以投影其他字段吗?

【问题讨论】:

  • 使用Distinct 而不使用Group By
  • 速度问题可能与索引有关。如果您在 ProductID 上有一个非聚集索引,那么它可以将其拉出,而无需点击聚集索引。此外,排序(分组所需的)非常占用处理器和内存。您的排序可能没有足够大的内存授权并且溢出到磁盘。查看您的执行计划可能表明存在问题(例如,黄色 ! 标记表示存在问题)。此外,如果您在运行前SET STATISTICS TIME, IO ON;,它会很好地总结您的数据是如何从磁盘读取的。
  • 您有建议。简短的回答是不缺少 DDL 的变化。索引可能会有所帮助。物化视图可能会有所帮助。也许现在是回顾导致非规范化的原因的好时机——因为那是真正的原因。还有一件事要考虑。大多数查询需要进行排序才能有用 - 您的查询没有 ORDER BY 子句,因此没有定义的顺序。如果顺序很重要,您的查询必须有一个 ORDER BY 子句。
  • 我们在表上有一个聚集列存储索引,因此更多索引可能无济于事。 @MostafaArmandi,我尝试过不同的,这给了我完全相同的性能。

标签: sql-server performance denormalization


【解决方案1】:

我评论了速度问题的潜在原因(主要可能是由于排序所需的读取和处理增加)。

但是,我对你的问题的主要理解是

  • 您的数据实际上只是按 productid 分组,但由于它是非规范化的,它还有其他与 productid 直接相关的列
  • 因为您要对所有三个字段进行分组,所以速度很慢 - 您希望仅通过 productid 分组来加快速度

答案 1:索引

如果您在这些列上放置索引,则它已经被预先排序。但是,我的猜测是您的索引已经非常密集,因此更多的索引可能会导致问题。如果没有,请尝试在所有 3 个字段上添加索引,或者如果某些字段太大(例如 nvarchar(4000)),则在其余字段上添加索引,并“包含”大字段。

调整查询

对于这些,我们接受我们必须在查询中进行排序。问题是如何减少处理和/或读取。

没有统计数据和/或执行计划,这可能很难 - 但这里有一些建议。

我相信,下面的第一种方法不会真正奏效,但值得一试。

select productid, MAX(productname) as productname, MAX(subcategoryid) as subcategoryid
from visitevents
group by productid

我希望你看到我正在尝试做的事情 - 将 group-by 减少到一个字段。但是,由于它仍然需要进行排序以获得最大值,所以它可能仍然很慢(尽管它们没有被排序在一起,它可能会快一点)。

另一种方法是对 productid 进行排序/组并获取 any 的相应值(您不在乎哪个)。一种方法是

; WITH cte AS 
  (select productid, productname, subcategoryid,
   ROW_NUMBER() OVER (PARTITION BY productid ORDER BY productid) AS rn
   from visitevents
  )
SELECT productid, productname, subcategoryid
FROM cte
WHERE cte.rn = 1

对于上述内容,它获取所有数据,按 productid 对其进行排序,然后(有点随机)为该组中的每一行分配行号。然后它只获取所有第一行。

太丑了。它有点滥用窗口函数 (PARTITION BY productid ORDER BY productid???) 根据定义,这个 ORDER BY 什么都不做,但包含在内是因为您必须在 ROW_NUMBER 中有一个 ORDER BY。

什么都不做是你想要的——不想把 CPU 周期花在额外的种类上。所以希望它会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-27
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 2016-05-13
    • 2018-06-06
    相关资源
    最近更新 更多