将数据分组为模糊间隙和孤岛

bie*_*ski 1 t-sql sql-server

这本质上是一个间隙和岛屿问题,但它是非典型的。我确实将示例缩减到最低限度。我需要识别超过特定阈值的间隙,并且重复不会成为问题,尽管此示例删除了它们。
在任何情况下,使用 ROW_NUMBER() 的常见解决方案都没有帮助,因为即使是 1 的间隙也无法处理,并且间隙值是“现实生活”中的参数。

下面的代码实际上可以正确运行。而且速度超级快!但如果你看看它,你就会明白为什么人们对依赖它相当害羞。该方法首次发布于 9 年前,http ://www.sqlservercentral.com/articles/T-SQL/68467/,我已经阅读了全部 32 页的评论。除了说“这不是有记录的行为”之外,没有人成功地找出其中的漏洞。我在 2005 年到 2019 年的每个版本上都尝试过,效果很好。

问题是,除了使用游标或 while 循环逐一查看数百万行之外,这需要多长时间,因为我在 30 分钟后取消了。- 是否有一种“受支持”的方法可以在合理的时间内获得相同的结果?即使慢 100 倍也会在 10 分钟内完成 4M 行,但我找不到接近这个目标的方法!

CREATE TABLE #t (CreateDate   date not null
                ,TufpID       int not null
                ,Cnt          int not null
                ,FuzzyGroup   int null);
ALTER TABLE #t ADD CONSTRAINT PK_temp PRIMARY KEY CLUSTERED (CreateDate,TufpID);

-- Takes 40 seconds to write 4.4M rows from a source of 70M rows.
INSERT INTO #T
    SELECT X.CreateDate
          ,X.TufpID
          ,Cnt          = COUNT(*)
          ,FuzzyGroup   = null
      FROM SessionState SS
     CROSS APPLY(VALUES (CAST(SS.CreateDate as date),SS.TestUser_Form_Part_id)) X(CreateDate,TufpID)
     GROUP BY X.CreateDate
             ,X.TufpID
 ORDER BY x.CreateDate,x.TufpID;

-- Takes 6 seconds to update 4.4M rows.  They WILL update in clustered index order!
-- (Provided all the rules are followed - see the link above)
DECLARE @FuzzFactor int = 38 
DECLARE @Prior      int = -@FuzzFactor; -- Insure 1st row has it's own group
DECLARE @Group      int;
DECLARE @CDate      date;
UPDATE #T
   SET @Group = FuzzyGroup  = CASE WHEN t.TufpID - @PRIOR < @FuzzFactor AND t.CreateDate = @CDate
                                   THEN @Group ELSE t.TufpID END
      ,@CDate               = CASE WHEN @CDate = t.CreateDate THEN @CDate ELSE t.CreateDate END
      ,@Prior               = CASE WHEN @Prior = t.TufpID-1   THEN @Prior + 1 ELSE t.TufpID END
  FROM #t t WITH (TABLOCKX) OPTION(MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

执行上述操作后,FuzzyGroup 列包含组中 TufpID 的最低值。IOW 第一行(按聚集索引顺序)包含它自己的 TufpID 列的值。此后,每行都会获得相同的值,直到日期更改或超出间隙大小(在本例中为 38)。在这些情况下,当前的 TufpID 会成为放入 FuzzyGroup 中的值,直到检测到另一个更改。因此,6 秒后,我可以运行按 FuzzyGroup 分组的查询并分析岛屿。

在实践中,我也在同一次传递中进行了一些运行计数和总计,因此需要 8 秒而不是 6 秒,但如果需要的话,我可以很容易地使用窗口函数完成这些操作,所以我将它们保留下来。

这是最小的表,我最终需要处理 100M 行。因此 10 分钟的 4.4M 可能还不够好,但它是一个起点。

Mar*_*ith 5

这应该相当有效,并避免依赖无证行为

WITH T1
     AS (SELECT *,
                PrevTufpID = LAG(TufpID)
                               OVER (PARTITION BY CreateDate
                                         ORDER BY TufpID)
         FROM   #T),
     T2
     AS (SELECT *,
                _FuzzyGroup = MAX(CASE
                                    WHEN PrevTufpID IS NULL
                                          OR TufpID - PrevTufpID >= @FuzzFactor
                                      THEN TufpID
                                  END)
                                OVER (PARTITION BY CreateDate
                                          ORDER BY TufpID ROWS UNBOUNDED PRECEDING)
         FROM   T1)
UPDATE T2
SET    FuzzyGroup = _FuzzyGroup 
Run Code Online (Sandbox Code Playgroud)

执行计划对聚集索引进行单次有序扫描,然后行值流经一些窗口函数运算符并进入更新。

在此输入图像描述

  • 我找不到按钮。我检查了[有用]箭头!为什么网站需要在他们的网站上添加如此多的符号,这些符号完全没有意义,除非你漂浮在每一个符号上直到找到有用的东西。触摸屏没有任何浮动选项当然没有帮助,因此如果不尝试就几乎不可能发现某些东西的作用,并且永远不能保证如果您碰到错误的东西可以撤消!我很抱歉继续运行 - 而且我没有立即找到并检查它。 (2认同)