想象你的手机相册:一家人出门旅游,每分钟拍一张,一天下来几千张照片。手机提示“存储空间不足”时,你怎么办?聪明的做法是——按小时挑一张“代表照”,比如中午拍一张、下午拍一张;再把整趟旅行整理成一本“旅行相册”,以后想回忆,翻相册就行,不用在一万张原图里翻到手指发麻。时序数据库面对的数据,恰恰就是这种“每秒都在拍照片”的场景:服务器的CPU使用率、机房的温度、APP的访问量,每一秒都在产生新数据。一年下来,一个指标就有三千多万条记录。降采样与连续聚合,就是给数据做“相册整理”:降采样负责把高频数据按时间窗口提炼成低频概要,连续聚合负责“旅行一结束就立刻装订好相册”,让未来的大跨度查询不用再翻原片。今天,我们就用这本“相册”的整理之道,把降采样和连续聚合讲透。

岗位关联

掌握时序数据降采样与连续聚合,你就掌握了监控与IoT系统“降本增效”的核心杠杆——既能省下九成存储,又能让大跨度查询毫秒返回,这是时序平台架构师的基本功。

目录
  1. 可视化演示
  2. 数据膨胀难题
  3. 降采样机制
  4. 聚合函数族
  5. 连续聚合引擎
  6. 查询优化法
  7. 工程实践
  8. 取舍权衡
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

数据膨胀难题

手机的相册正在被照片塞爆:每分钟一张,一天就是一千多张,一年三十多万张。每张照片都舍不得删,可手机越来越慢、云盘越来越贵,翻旧照片也越来越难——这就是时序数据面临的真实处境。服务器CPU、内存、磁盘利用率,或机房里一排传感器的温度读数,都以“每秒一条”的节奏持续写入。单个指标一年就有三千多万条记录,而一个生产系统往往监控着成百上千个指标。

把镜头拉近看技术本质。这种按时间顺序持续追加、只增不改的数据叫时序数据。它的写入永远很轻快,痛点全在“存”和“查”上:全量保留代价高昂,跨月、跨年的查询要在海量记录里逐条扫描,慢得让人抓狂。更扎心的是,这些数据里绝大多数是“重复的日常”——CPU在 30% 到 40% 之间小幅波动,这种细节对长期趋势分析几乎没有价值。

数据膨胀就像相册越堆越厚,想靠“多买手机内存”硬扛绝非长久之计。真正聪明的做法,是像整理相册一样,把“平凡的照片”浓缩成几张“代表照”——这正是降采样要做的事。

V=r×T\displaystyle V = r \times T
总数据量 = 每秒采样率 × 采集总秒数。这是数据膨胀的“数学账单”。
  1. 总数据量 VV 表示一段时间内累积的全部数据点条数,单位是“条”
    VV
  2. 每秒采样率 rr 指每秒写入的数据条数,比如一台机器每秒上报 1 条 CPU 指标
    rr
  3. 总时长 TT 是采集持续的总秒数,1 天是 86400 秒,1 年约 3154 万秒
    TT
  4. 乘法运算把每秒条数与总秒数相乘,就得到数据总量,例如每秒 1 条、连续 1 年,约产生 3153 万条
    r×Tr \times T

降采样机制

整理相册时,你不会把每一张照片都保留在“精选集”里:每个小时挑一张最清晰的当作代表,一天就只剩二十多张,好找又好存。降采样就是时序世界里的“精选照片”:把时间轴切成固定长度的小窗口,每个窗口内的所有数据点,被一个聚合值替代。

这个“切窗口”的动作叫时间窗口划分。假设采集频率是每秒一条,我们把时间切成每 60 秒一个桶,第 1 秒到第 60 秒进 1 号桶,第 61 秒到第 120 秒进 2 号桶,以此类推。每个桶里原本有 60 个原始点,经过聚合后只输出 1 个代表值,数据量立刻缩减为原来的六十分之一。这就是“精度换规模”:我们放弃了秒级的细枝末节,换来了数量级的存储下降。

降采样不是在“毁掉”数据,而是在替数据做减法:把琐碎的秒级波动折叠成清晰的分钟级趋势。配合保留策略使用——原始数据只留 7 天,降采样后的概要数据留 1 年——相册就能既装得下历史,又翻得动当下。

vˉw=1nw∑t∈Wvt\displaystyle \bar{v}_w = \frac{1}{n_w}\sum_{t \in W} v_t
每个时间窗口内所有原始值的算术平均,就是该窗口的代表值。这是最常用的降采样聚合方式。
  1. 窗口 WW 是时间轴上的一段固定区间,比如“第 0 秒到第 59 秒”
    WW
  2. 窗口内点数 n_wn_w 表示落在窗口 W 内的原始数据点个数,窗口 60 秒、每秒 1 条时,n_w = 60
    nwn_w
  3. 求和符号把窗口内所有点的值 v_t 逐项相加,v_t 读作“时刻 t 的取值”
    ∑t∈Wvt\displaystyle \sum_{t \in W} v_t
  4. 取平均用总和除以点数,得到该窗口的代表值,记作 \bar{v}_w
    1nw∑t∈Wvt\displaystyle \frac{1}{n_w}\sum_{t \in W} v_t

聚合函数族

整理代表照时,选哪一张取决于你想留住什么:想记录“最灿烂的一刻”就挑最好看的,想表达“普遍状态”就挑最普通的。降采样窗口里的聚合函数,就是一个个不同口味的“选片标准”。均值(AVG)给出窗口内的典型水平,适合看整体趋势;最大值(MAX)和最小值(MIN)锁定极端情况,是异常告警的哨兵;计数(COUNT)和求和(SUM)核算总量,比如一分钟内请求总数。

还有一个高手偏爱的角色——分位数(P95)。它回答的问题是:“95% 的情况下,延迟都在这个值以内?”均值会被极端值拉偏,P95 却能诚实地暴露长尾。举个例子:某窗口内请求延迟分别是 10ms、12ms、11ms、300ms、13ms,均值高达 69ms,看着吓人;而 P95 会告诉你“95% 的请求都落在 13ms 附近”,这才是真实体验。监控场景里,P95 聚合是发现“少数慢请求拖垮体验”的利器。

选片标准决定了相册的性格,聚合函数决定了数据概要的“口味”。但无论选哪种口味,每次手动计算都要从头扫一遍窗口内所有数据——如果有一个“自动装订相册”的机制,让代表值提前算好、随新照片自动更新,那该多省事?这正是连续聚合的登场时刻。

vmax⁡=max⁡t∈Wvt,q95(W)=min⁡{x:P(vt≤x)≥0.95}\displaystyle v_{\max} = \max_{t \in W} v_t, \qquad q_{95}(W) = \min\{x : P(v_t \le x) \ge 0.95\}
左侧:取窗口内最大值;右侧:找到最小的 x,使得窗口内 95% 的值都不超过它,这个 x 就是 P95 分位值。
  1. 最大值符号max 表示从窗口 W 的所有 v_t 中挑出数值最大的那个,用于捕捉峰值
    max⁡t∈Wvt\displaystyle \max_{t \in W} v_t
  2. 概率条件P(v_t ≤ x) 表示“窗口内取值不超过 x 的点占比”,是一个 0 到 1 的概率
    P(vt≤x)\displaystyle P(v_t \le x)
  3. 下确界 min在满足“超过 95%”这个条件的所有 x 里,取最小的那一个
    min⁡{x:⋯≥0.95}\displaystyle \min\{x : \cdots \ge 0.95\}
  4. 综合含义q_{95}(W) 就是窗口 W 的 P95 分位值——95% 的数据点都比它小,它代表大多数情况的上限
    q95(W)=min⁡{x:P(vt≤x)≥0.95}\displaystyle q_{95}(W) = \min\{x : P(v_t \le x) \ge 0.95\}

连续聚合引擎

旅行结束后,你立刻花一个晚上把几千张照片整理成一本相册。之后每拍一张新照片,你只是把新照片夹进相册最后一页,绝不会推翻整本相册重做。连续聚合就是时序数据库里的“自动装订机”:系统预先定义好常用时间窗口(比如 1 分钟均值、1 小时最大值),后台任务持续计算并把结果物化成一张实实在在的表——这类由查询结果“实体化”而来的表,就叫物化视图。

物化视图与普通视图最大的区别是“真的存储”。普通视图只是一句 SQL 的快捷方式,查询时照样扫原始数据;物化视图则把计算结果落盘成一张独立的表,查询直接读它。为了保证画面不过期,数据库会按刷新调度周期性地后台重算。而重算的聪明之处在于增量更新:新数据到达时,只刷新受影响的少数窗口,已经算好的历史窗口一概不动。传感器每秒钟都在产生新数据,增量更新让连续聚合的维护成本几乎可以忽略不计。

有了这本“自动更新的相册”,当老板问起“过去一年 CPU 平均使用率怎么样”,系统不用再去翻 3 千万张原始照片,直接翻开装订好的年度相册,一秒钟就给出答案。接下来,我们仔细看看查询是怎么走上这条快车道的。

Cinc=O(Δt),Cfull=O(T),Cinc≪Cfull\displaystyle C_{\mathrm{inc}} = O(\Delta t), \qquad C_{\mathrm{full}} = O(T), \qquad C_{\mathrm{inc}} \ll C_{\mathrm{full}}
增量更新的开销只和新到达的数据量有关,远小于每次都全量重算的代价。
  1. 增量开销 C_inc只处理新到达的 Δt 秒数据,成本与 Δt 成正比
    Cinc=O(Δt)\displaystyle C_{\mathrm{inc}} = O(\Delta t)
  2. 全量开销 C_full每次重算要遍历整个历史区间 T 的全部原始数据
    Cfull=O(T)\displaystyle C_{\mathrm{full}} = O(T)
  3. 远小于符号新数据通常只有秒级规模,历史却是年级规模,因此增量成本远低于全量成本
    Cinc≪Cfull\displaystyle C_{\mathrm{inc}} \ll C_{\mathrm{full}}

查询优化法

你永远不会为了回忆“去年夏天去了哪”而逐张翻看三万张照片——你直接翻开旅行相册,找到“去年七月”那一页。连续聚合对查询的优化,正是把“逐张翻照片”变成“翻相册”。当用户发起一个跨越数周、数月甚至数年的大跨度查询,数据库会识别出查询的时间范围与聚合方式,优先读取预计算好的物化视图,而不是扫描原始数据表——这个行为叫查询下推。

结果直接复用带来两个显著收益:一方面,大跨度查询免扫原始数据,磁盘 IO 从“读几百 GB”降到“读几 MB”;另一方面,响应时间从秒级甚至分钟级跃升到毫秒级。在监控大屏、告警规则和报表系统中,这种差异是肉眼可见的:左边同事的图表还在转圈,右边你的图表已经渲染完毕。聚合粒度越粗、时间跨度越大,收益越明显。

查询优化让“翻相册”成为默认路径,但这一切的前提是工程上把机制落地到位。不同的业务场景,相册的整理方式也不同:监控系统有监控的整法,物联网有物联网的整法。我们来聊聊实战。

Ndown=Nrawm\displaystyle N_{\mathrm{down}} = \frac{N_{\mathrm{raw}}}{m}
降采样后的数据点数量约为原始数量的 m 分之一,m 是窗口长度(秒)。查询扫描量也随之同比缩小。
  1. 原始点数 N_raw窗口聚合前,原始表里的总数据条数
    NrawN_{\mathrm{raw}}
  2. 窗口长度 mm 代表聚合窗口的秒数,窗口越大,压缩越狠
    mm
  3. 降采样后点数 N_down用总条数除以窗口长度,得到聚合后的概要条数
    Nrawm\displaystyle \frac{N_{\mathrm{raw}}}{m}

工程实践

把相册整理流程做成一条自动化流水线:相机不停拍,后台每隔几小时自动精选,满一年自动装订成册,旧的原片按规矩进冷宫。时序数据库的工程实践也是如此。监控场景是最典型的用户:Prometheus 这类监控系统采集 CPU、内存、网络流量等指标,原始数据保留 7 天用于排障,同时定义连续聚合任务,产出 5 分钟均值、1 小时均值和每天最大值,保留一年用于容量规划。

物联网场景同样受益巨大:智慧楼宇里上千个温湿度传感器、电表、水表每秒上报数据,按小时聚合后一张表就能容纳整栋楼十年的环境趋势。实际效果可以用一个数字概括——存储成本降九成。窗口取 60 秒时,数据量缩减到原来的 1/60,存储成本下降超过 98%。配置指引上,核心原则是“近细远粗”:新数据用秒级窗口保留,越老的数据用越粗的窗口,冷热分层各得其所。

工程落地之后,我们还要冷静地问一句:把相册从三万张精简到三百张,真的没有代价吗?有。精度与成本之间的拔河,是降采样永恒的主题。

S=1−NdownNraw=1−1m\displaystyle S = 1 - \frac{N_{\mathrm{down}}}{N_{\mathrm{raw}}} = 1 - \frac{1}{m}
存储节省率:原始数据换成概要数据后,能省下的空间比例。窗口越大,省得越多。
  1. 节省率 SS 表示降采样后节省的存储比例,1 代表全部省下,0 代表没省
    SS
  2. 占比计算N_down / N_raw 表示概要数据占原始数据的比例,是分子的缩减倍数
    NdownNraw\displaystyle \frac{N_{\mathrm{down}}}{N_{\mathrm{raw}}}
  3. 代入窗口 m由于 N_down = N_raw / m,占比简化为 1/m,因此 S = 1 - 1/m
    1−1m\displaystyle 1 - \frac{1}{m}
  4. 实例验证m = 60 秒时,S ≈ 98.3%,也就是存储体积缩减到原来的 1.7%
    1−160≈0.983\displaystyle 1 - \frac{1}{60} \approx 0.983

取舍权衡

相册整理得越狠,省下的空间越多,但丢失的细节也越多。如果你把照片全部按“每小时一张”精选,恰好错过了孩子第一次站起来的瞬间,那这本相册再省空间也失去了意义。降采样的取舍同样微妙:窗口越大,数据越少、查询越快,但求均值会掩盖短暂尖峰——一次 500ms 的延迟抖动,混在 60 秒的均值里几乎无影无踪。

所以优秀的时序数据库都提供“粗细结合”的保留策略:关键语义必须保全。告警场景下,MAX 聚合必须保留,因为“是否突破阈值”是生死线;容量规划里,日均值和 P95 更有价值。陈旧数据并非垃圾——一年前的 CPU 趋势对判断服务器扩容节奏依然重要,只是不需要秒级精度。权衡的本质是给不同年龄段的数据分配不同的“相册精细度”:热数据原样珍藏,温数据摘要留存,冷数据只留骨架。

这就是降采样与连续聚合的完整哲学:用可控的精度牺牲,换取数量级的成本与性能收益,再把最关键的语义牢牢攥在手里。相册不必每张都留,但值得留的,一张都不能丢。

Vtotal=r⋅Draw+rm⋅Ddown\displaystyle V_{\mathrm{total}} = r \cdot D_{\mathrm{raw}} + \frac{r}{m} \cdot D_{\mathrm{down}}
总存储 = 原始数据保留量 + 降采样概要数据保留量。通过调节保留天数与窗口大小,找到精度和成本的最佳平衡点。
  1. 原始数据体积r × D_raw,每秒 r 条数据、保留 D_raw 天,所占的空间
    r⋅Draw\displaystyle r \cdot D_{\mathrm{raw}}
  2. 概要数据体积(r / m) × D_down,每秒 r 条聚合成每秒 r/m 条、保留 D_down 天
    rm⋅Ddown\displaystyle \frac{r}{m} \cdot D_{\mathrm{down}}
  3. 总空间两部分相加,就是这套保留策略的总存储占用
    Vtotal\displaystyle V_{\mathrm{total}}
  4. 调整旋钮调大 m 或缩短 D_raw,存储下降、精度下降;反之精度回升、成本上升
    r⋅Draw+rm⋅Ddown\displaystyle r \cdot D_{\mathrm{raw}} + \frac{r}{m} \cdot D_{\mathrm{down}}

AI 应用场景

云监控平台指标趋势分析

阶段:数据治理与存储优化

解决的问题:传统做法把一年内所有秒级指标全量保存在热存储中,存储成本随机器数量线性爆炸;“查询近 30 天 CPU 平均使用率”需要扫描几十亿行,报表响应以分钟计。AI 能力形态表现为连续聚合:预计算 5 分钟均值与 1 小时均值的物化视图,趋势类查询自动命中预计算结果。

具体案例:某云厂商可观测性平台对 2000 台服务器的 CPU、内存指标做降采样,原始数据保留 7 天,连续聚合结果保留 1 年。改造后,30 天趋势报表从 80 秒降至 0.2 秒,存储成本下降 85%。

智慧楼宇物联网传感网

阶段:数据生命周期管理

解决的问题:上千个温湿度、电表、水表传感器每秒上报数据,全量存储一周就耗尽机房磁盘。通过窗口降采样按小时求均值与极值,既保留环境变化趋势,又保留“设备异常高温”的告警语义,大跨度能耗分析无需触碰原始数据。

具体案例:某智慧园区部署 1200 个传感器,原始数据每秒 1 条、保留 3 天,降采样为小时均值后保留 3 年,历史能耗曲线查询响应从分钟级变为秒级。

电商大促流量监控与容量规划

阶段:时序洞察与容量规划

解决的问题:大促期间每秒订单量、QPS、接口延迟剧烈波动,全量历史数据难以支撑“去年双十一同时段表现如何”这类长跨度对比查询。连续聚合预计算分钟级均值与 P95 延迟,既保留长尾信息,又让跨年容量对比即时可用。

具体案例:某电商平台在大促前用连续聚合重建近三年大促时段的分钟级摘要,容量规划团队在 10 秒内完成历史同期对比,精准预测了本次大促的峰值流量规模。

Python 演示

python105 行
import mathimport randomimport time  class TimeSeriesDB:    """小型时序数据库: 存原始数据 + 降采样"""    def __init__(self):        self.data = []        self.window_sec = 60     def ingest(self, points):        # 批量写入 (timestamp, value) 点        self.data.extend(points)     def raw_points(self):        return len(self.data)     def down_sample(self, window_sec, mode="avg"):        # 按窗口把高频数据聚合为低频概要, 返回 [(窗口起始秒, 聚合值)]        result = []        idx = 0        n = len(self.data)        while idx < n:            window_id = self.data[idx][0] // window_sec            vals = []            while idx < n and self.data[idx][0] // window_sec == window_id:                vals.append(self.data[idx][1])                idx += 1            if mode == "avg":                agg = sum(vals) / len(vals)            elif mode == "max":                agg = max(vals)            elif mode == "min":                agg = min(vals)            else:                agg = sum(vals)            result.append((window_id * window_sec, round(agg, 2)))        return result  class ContinuousAggregator:    """连续聚合: 预计算窗口统计, 新数据只做增量更新"""    def __init__(self, window_sec):        self.window_sec = window_sec        self.sum_map = {}        self.count_map = {}        self.max_map = {}     def insert(self, points):        for ts, v in points:            w = ts // self.window_sec            self.sum_map[w] = self.sum_map.get(w, 0.0) + v            self.count_map[w] = self.count_map.get(w, 0) + 1            if w in self.max_map:                self.max_map[w] = max(self.max_map[w], v)            else:                self.max_map[w] = v     def query(self, start_w, end_w):        # 直接读预计算摘要, 不扫描原始数据        out = []        for w in range(start_w, end_w + 1):            if w in self.sum_map:                avg = self.sum_map[w] / self.count_map[w]                out.append((w * self.window_sec, round(avg, 2), self.max_map[w]))        return out  def gen_sensor_data(n=90000, base=30.0, amp=10.0):    # 模拟温度传感器每秒上报一条数据    rng = random.Random(42)    points = []    for i in range(n):        v = base + amp * math.sin(i / 300.0) + rng.gauss(0, 1.5)        points.append((i, round(v, 2)))    return points  def main():    raw = gen_sensor_data(90000)          # 90,000 条秒级原始数据    db = TimeSeriesDB()    db.ingest(raw)     t0 = time.time()    ds = db.down_sample(60, "avg")        # 降采样: 60 秒窗口求平均    t1 = time.time()     agg = ContinuousAggregator(60)    agg.insert(raw)                        # 预计算所有窗口摘要     t2 = time.time()    res = agg.query(0, 1499)              # 查最近 25 小时的窗口摘要    t3 = time.time()     print("原始点数:", db.raw_points())    print("降采样后:", len(ds), "点, 耗时 %.4fs" % (t1 - t0))    print("连续聚合查询窗口数:", len(res), ", 耗时 %.6fs" % (t3 - t2))    print("数据量缩减至原规模: %.2f%%" % (len(ds) / db.raw_points() * 100))    if len(res) > 84:        print("示例窗口 5040s: avg=%.2f max=%.2f" % (res[84][1], res[84][2]))  if __name__ == "__main__":    main()
目的:模拟 9 万条秒级温度数据,演示降采样如何把数据量压缩到 1/60,以及连续聚合如何通过预计算让大跨度查询“零扫描”。
  1. db.down_sample(60, "avg")按 60 秒窗口求均值,是降采样的核心入口
  2. self.sum_map[w] = self.sum_map.get(w, 0.0) + v增量累加窗口总和,新数据只更新它所在的窗口
  3. self.count_map[w] = self.count_map.get(w, 0) + 1增量统计窗口内点数,为求均值提供分母
  4. agg.insert(raw)一条命令完成全量预计算,等价于“旅行结束后立刻装订相册”
  5. agg.query(0, 1499)直接读预计算摘要表,查询结果在内存字典中瞬时返回

常见误区

误区降采样只是把数据“压缩”了一下,查询结果应该和原始数据一模一样,顶多文件变小了。

正解降采样是真正的“丢数据”——每个窗口只保留一个代表值,窗口内的细节被永久丢弃。就像每小时挑一张代表照,其余 59 张必然消失。查询均值还能反映趋势,但要查“某天 10:03:17 那一秒的精确值”,降采样后的数据给不出答案。明确这一点,才能正确设计保留策略。

为何常见:日常中“压缩图片”不会改变内容,容易让人把数据压缩和降采样混为一谈。

误区我写个 cron 任务,每五分钟跑一次 SQL 聚合,不就实现连续聚合了吗?没必要用数据库内置功能。

正解定时脚本是全量重算,每次都要扫历史数据,成本高且数据有窗口空白期。真正的连续聚合由数据库内建调度器驱动,采用增量更新:新数据到达只刷新受影响窗口,历史窗口分毫不动,查询还能自动下推到预计算结果上。用脚本模拟,既慢又容易出错。

为何常见:很多人只见过“定时跑批”这种通用 ETL 思路,不知道数据库层面有专门的原生优化。

误区窗口越大,数据越少,存储越省,干脆把窗口设成 24 小时,一年只有 365 个点,多痛快。

正解窗口过大的代价是趋势失真和语义丢失。24 小时均值会让一天的负载曲线变成一条直线,深夜低谷和白天高峰全被抹平,告警和容量规划都失去依据。P95、MAX 等函数在超大窗口下同样失去意义。窗口选择应匹配业务决策粒度:告警看秒级极值,趋势看分钟均值,规划看日级汇总。

为何常见:只盯着“省存储”这个单一指标,忽略了数据概要的核心使命是“仍能回答业务问题”。

误区既然有了降采样概要,原始数据就没什么用了,删掉能省最多空间。

正解降采样数据回答“趋势”问题,原始数据回答“取证”问题——某次故障的精确现场、某次突刺的完整波形,只在原始数据里存在。合理做法是分层保留:原始数据保留短周期(7 天),概要数据保留长周期(1 年)。直接把原始数据全部删掉,等于把监控系统的“事故黑匣子”也扔了。

为何常见:只看到存储成本,没看到原始数据在故障排查中的不可替代价值。

误区连续聚合是预计算好的,查询它任何时候都会得到和全量计算完全一致的结果。

正解连续聚合的结果有“时效性窗口”。正在写入数据的窗口尚未闭合,它的聚合值是“截至当前的部分统计”;需要等窗口结束并刷新完成后,结果才与全量计算一致。很多系统的设计是“当前窗口的数据延迟可见”,比如查询最近 1 小时均值时,最后一分钟可能稍旧。理解刷新调度,才能设计出告警可接受的延迟。

为何常见:把“预计算”等同于“静态不变”,忽略了数据持续流入带来的动态更新问题。

面试题

Q1. 降采样的核心目标是什么?

单选题 · easy

  • A.提高数据采样精度
  • B.减少数据量降低存储成本← 正确答案
  • C.加速数据写入速度
  • D.改变数据字段类型

答案:B。降采样把高频数据按窗口聚合为低频概要,直接目标是压缩数据量、降低存储与查询成本,相当于给相册做精简。它不提高精度,也不改变字段类型,写入速度不是降采样要解决的问题。

Q2. 某系统每秒采集一次 CPU 数据,以 60 秒窗口做均值降采样,降采样后的数据分辨率为?

单选题 · mid

  • A.每分钟一个数据点← 正确答案
  • B.每秒一个数据点
  • C.每小时一个数据点
  • D.每天一个数据点

答案:A。每秒一条原始数据,按 60 秒窗口聚合,每个窗口输出一个均值点,因此分辨率是“每分钟一个点”,相当于从 60 张原图中挑一张代表照。

Q3. 关于连续聚合相比普通全量重算的优势,下列说法正确的有?

多选题 · mid

  • A.查询可直接复用已计算的窗口结果← 正确答案
  • B.每次查询仍要扫描全部原始数据
  • C.新数据到达时只需增量更新受影响的窗口← 正确答案
  • D.不需要存储任何预计算结果

答案:AC。连续聚合把窗口统计物化为独立表,查询直接复用;新数据只刷新受影响窗口,成本远低于全量重算。B 是普通查询的劣势,D 与连续聚合的本质(预计算存储)相悖。

Q4. 下列哪个函数适合作为降采样的聚合函数?

单选题 · easy

  • A.平均值← 正确答案
  • B.快速排序
  • C.数据去重
  • D.事务提交

答案:A。平均值把窗口内多个值浓缩为一个代表值,是经典聚合函数。排序和去重不产生窗口统计量,事务提交是数据库写入机制,与聚合无关。

Q5. 关于连续聚合的维护开销,描述正确的有?

多选题 · hard

  • A.新数据到达只需刷新受影响的时间窗口← 正确答案
  • B.每次刷新都必须重建全部历史窗口
  • C.窗口统计信息可以用累加、计数等方式增量维护← 正确答案
  • D.维护开销与数据到达速率完全无关

答案:AC。增量更新只处理新数据所在的窗口,维护成本与新增数据量成正比;均值可用“累加和 + 计数”增量维护。B 是低效的全量重算,D 忽略了数据速率是开销的决定因素。

Q6. 降采样窗口从 60 秒调整为 300 秒,输出数据量约为原来的?

单选题 · mid

  • A.五分之一← 正确答案
  • B.五倍
  • C.保持不变
  • D.六十分之一

答案:A。窗口越大,输出的聚合点越少。N_down = N_raw / m,从 60 秒调到 300 秒,m 扩大 5 倍,点数缩减为原来的 1/5,相当于相册从每小时一张变成每五小时一张。

Q7. 在时序监控中,P95 分位聚合主要用于解决什么问题?

单选题 · extreme

  • A.表示 95% 的请求延迟低于该值,暴露长尾← 正确答案
  • B.计算系统的总网络流量
  • C.备份原始数据到冷存储
  • D.校验写入数据的完整性

答案:A。P95 分位值回答“95% 的情况都在这个阈值以内”,能揭示被均值掩盖的长尾延迟。它不计算总量、不做备份、也不做完整性校验——它是聚合函数族中“看极端体验”的利器。

Q8. 某监控系统原始数据保留 7 天,降采样概要保留 1 年,这种设计体现了什么思想?

单选题 · hard

  • A.冷热分层的数据保留策略← 正确答案
  • B.数据库的主从复制机制
  • C.事务的隔离级别控制
  • D.索引的自动重建策略

答案:A。近期数据保留全细节(热),远期只保留概要(冷),正是冷热分层保留策略。它和主从复制、事务隔离、索引重建没有任何关系——本质是“近细远粗”的相册管理思路。

Q9. 时序数据规模膨胀会带来哪些直接问题?

多选题 · easy

  • A.存储成本随数据量急剧上升← 正确答案
  • B.大跨度时间范围查询变慢← 正确答案
  • C.磁盘空间被快速消耗殆尽← 正确答案
  • D.数据采样精度自动提升

答案:ABC。数据越多,存储成本越高、磁盘越紧张,全量扫描式的大跨度查询也越慢。膨胀不会自动提升精度,反而迫使系统降低精度来维持成本,所以 D 错误。

Q10. 查询“过去 30 天 CPU 平均使用率”时,下列哪条执行路径最优?

单选题 · mid

  • A.扫描 30 天的全部原始数据表
  • B.读取预计算的日级聚合物化视图← 正确答案
  • C.用索引逐条随机读取原始记录
  • D.每次查询时临时重建整张聚合表

答案:B。连续聚合已把日级均值物化为独立表,查询直接读表即可,扫描量最小。A、C 都要触碰海量原始数据,D 的“每次重建”开销比查询本身还高。这就像直接翻相册而不是翻三万张原片。