You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于MySQL滑动窗口统计带创建/更新时间的每小时待处理行数

实现方案

核心判定逻辑:对于某一整点区间[h, h+1小时),所有满足created_at < h+1小时 且(updated_at IS NULL 或 updated_at >= h+1小时)的行,都属于该小时的待处理行。


方案1:递归CTE生成时间序列+直接关联统计(适合中小数据量)

写法简单直观,适合数据量在十万级以下的场景:

SET @start_time = '2024-01-01 00:00:00'; -- 替换为你的查询起始时间
SET @end_time = '2024-01-07 23:00:00'; -- 替换为你的查询结束时间

WITH RECURSIVE hours AS (
    SELECT @start_time AS hour_start
    UNION ALL
    SELECT DATE_ADD(hour_start, INTERVAL 1 HOUR)
    FROM hours
    WHERE hour_start < @end_time
)
SELECT 
    h.hour_start,
    COUNT(i.id) AS pending_count
FROM hours h
LEFT JOIN items i
ON  i.created_at < DATE_ADD(h.hour_start, INTERVAL 1 HOUR)
AND (i.updated_at IS NULL OR i.updated_at >= DATE_ADD(h.hour_start, INTERVAL 1 HOUR))
GROUP BY h.hour_start
ORDER BY h.hour_start;

缺点是每个小时都会关联一次全表,数据量过大时性能较差。


方案2:事件累加计算(适合大数据量,性能更高)

将每条数据的生命周期拆为+1的创建事件、-1的更新事件,累加后按小时取最终值,仅需扫描一次items表,适合百万级以上数据量:

SET @start_time = '2024-01-01 00:00:00';
SET @end_time = '2024-01-07 23:00:00';
SET @current_pending = 0;

-- 先计算查询起始时间之前的初始待处理数
SELECT COUNT(*) INTO @init_pending
FROM items
WHERE created_at < @start_time
AND (updated_at IS NULL OR updated_at >= @start_time);

WITH all_events AS (
    -- 插入所有创建事件
    SELECT created_at AS event_time, 1 AS delta FROM items
    UNION ALL
    -- 插入所有更新事件
    SELECT updated_at AS event_time, -1 AS delta FROM items WHERE updated_at IS NOT NULL
    UNION ALL
    -- 插入小时占位事件,保证无数据的小时也能输出
    SELECT hour_start AS event_time, 0 AS delta 
    FROM (
        WITH RECURSIVE hours AS (
            SELECT @start_time AS hour_start
            UNION ALL
            SELECT DATE_ADD(hour_start, INTERVAL 1 HOUR)
            FROM hours WHERE hour_start < @end_time
        ) SELECT hour_start FROM hours
    ) h
),
sorted_events AS (
    -- 按时间排序计算待处理数的累加值
    SELECT 
        event_time,
        delta,
        @current_pending := @current_pending + delta AS running_total
    FROM all_events
    WHERE event_time BETWEEN @start_time AND DATE_ADD(@end_time, INTERVAL 1 HOUR)
    ORDER BY event_time
)
-- 按小时分组取每个小时最后一个累加值作为该小时的待处理数
SELECT 
    DATE_FORMAT(event_time, '%Y-%m-%d %H:00:00') AS hour_start,
    MAX(CASE WHEN rn = 1 THEN running_total ELSE @init_pending END) AS pending_count
FROM (
    SELECT 
        event_time,
        running_total,
        ROW_NUMBER() OVER (PARTITION BY DATE_FORMAT(event_time, '%Y-%m-%d %H:00:00') ORDER BY event_time DESC) AS rn
    FROM sorted_events
) t
WHERE rn = 1
AND hour_start BETWEEN @start_time AND @end_time
ORDER BY hour_start;

如果你的MySQL版本低于8.0不支持CTE,可以用临时表替代递归CTE生成时间序列,也可以提前维护一张独立的时间维度表提升查询效率。


内容的提问来源于stack exchange,提问作者est

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 01:15:03