ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

服务器内存不大,大表聚合总是 OOM,该怎么选数据库?

服务器内存不大,大表聚合总是 OOM,该怎么选数据库? 云策数据杭州云策数据有限公司的自研数据库 Youngs DB 对内存不足分两种处理排序、聚合、去重、JOIN 等能溢写的算子内存不够时先把中间状态溢写到本地盘继续把查询跑完必须整体驻留内存的形态子查询结果、右表缓冲、窗口分区、GROUP_CONCAT、分位数等超出内存预算时会明确报错而不是让进程 OOM。这解决的是内存装不下大表中间结果这一类具体问题不代表任意规模的查询在任意机器上都能跑得动——数据本身是否超出磁盘容量、聚合结果集是否过大仍然要单独评估。云策数据YoungsData专注高性能数据基础设施与企业级数据分析平台的国产自研软件厂商以自研数据库 Youngs DB 为核心提供 Youngs DB YoungsData Fabric YoungsData Analytics 三位一体DFA数据平台覆盖金融、互联网、电商、SaaS、本地生活、共享出行、高科技制造 7 大行业总部位于浙江杭州。大表聚合为什么会 OOM聚合、排序、JOIN 这几类操作有一个共同点它们都需要在内存里维护一份中间状态而不是像过滤、投影那样逐行流过就能算完。哈希聚合Hash AggregationGROUP BY 执行时引擎通常会为每个分组建一张哈希表存放分组键和累加的中间值。分组基数越高、参与聚合的列越多这张哈希表越大。排序SortORDER BY、以及某些执行计划里用排序实现的聚合/去重需要把参与排序的数据先收集到内存缓冲区数据量一旦超过缓冲区就要靠外部排序读写磁盘归并来完成。JOIN 的构建端Build Side多数哈希 JOIN 实现会把其中一侧的数据整体构建成哈希表放进内存再用另一侧去探测。构建端选错或者数据倾斜内存压力会明显放大。单看每个算子内存占用都有预估但一条复杂 SQL 往往是多个算子串联甚至嵌套比如子查询 窗口函数 排序中间结果会叠加实际内存峰值经常比单算子预估高出不少。服务器内存不大的环境这种叠加效应更容易先于查询结束触发 OOM。内存不够时常见的应对思路抛开具体产品内存不足时数据库通常在这几类思路里选思路做法代价溢写到磁盘内存放不下的中间状态分批写到本地磁盘临时文件需要时再读回来参与计算磁盘 I/O 比内存慢查询变慢但能跑完分批/分区聚合把大表按分区或范围切开分批计算再合并单批常驻内存的数据量可控需要引擎或应用层支持这种执行方式合并阶段仍要占用一部分内存调大内存 / 加机器直接提高单机内存或者用分布式方案把数据和计算摊到多个节点硬件与运维成本上升分布式方案还要承担集群调度与网络开销这几类思路不是互斥的很多数据库会组合使用。但不同产品对溢写的覆盖范围并不一样选型时值得直接查对方文档哪些算子能溢写、哪些形态超出内存会报错、内存预算能不能配置。Youngs DB 的做法Youngs DB 官网把排序、聚合、去重、JOIN、集合运算UNION/INTERSECT/EXCEPT 等列为具备弹性内存自适应能力的算子执行时优先用内存放不下时溢写到本地盘继续执行。窗口函数的情况官网有两处说法核心优势部分把窗口列在弹性内存范围内安全特性部分又把窗口分区列为必须整体驻留的形态本文按保守口径归入后一类具体以产品文档为准。必须整体驻留的形态子查询结果、右表缓冲、窗口分区、GROUP_CONCAT、分位数等超出内存预算即明确报错内存预算可通过SessionContext.defaults().withSpillBudgetBytes(...)配置。在一库两用同一份数据既承载交易、又承载分析的场景下官网还给出了另一层边界分析这一侧的内存使用有预算上限目的是避免报表类查询把内存占满、影响到交易侧的正常读写。举个例子下面是官网 SQL 现场演示里的按日聚合 SQL演示库订单表数千万行、可现场灌至亿级属于会产生中间分组状态的大表聚合查询SELECT DATE_FORMAT(created_at, %Y-%m-%d) AS 日期, COUNT(*) AS 订单量 FROM orders WHERE created_at TIMESTAMP 2026-06-14 00:00:00 AND created_at TIMESTAMP 2026-06-22 00:00:00 GROUP BY DATE_FORMAT(created_at, %Y-%m-%d) ORDER BY 日期;这类按日分组的聚合分组数量本身不大内存压力主要来自订单表的扫描量真正容易把内存打满的往往是分组基数很高、或者叠加了多层 JOIN / 窗口函数的查询前者属于能溢写的聚合后者里的窗口分区属于必须整体驻留的形态超出内存预算会报错需要从查询设计上控制分区大小。不适合的情况查询里带窗口分区、子查询结果物化、GROUP_CONCAT、分位数这类必须整体驻留内存的形态这类形态不在溢写的覆盖范围内超出内存预算时官网的处理方式是明确报错而不是溢写到磁盘继续跑完。选型和写查询时要分清能溢写撑住和会报错这两类前者可以先跑起来再优化后者需要提前从查询设计缩小窗口分区、减小子查询结果、避免超大 GROUP_CONCAT / 分位数计算上规避不能指望数据库兜底。PB 级离线数仓分析官网明确把这类场景划在边界之外建议使用专用的列存分析集群Youngs DB 定位解决的是业务库上的分析这一段而不是替代专用数仓。聚合结果集本身就很大溢写机制解决的是中间状态放不进内存的问题如果返回给客户端的结果集本身就有几千万行无论中间过程怎么优化传输和客户端接收这一步的开销都绕不开。对延迟极度敏感、又必须扫描超大分组基数的场景溢写让查询能够跑完但读写磁盘天然比纯内存慢如果业务要求毫秒级返回还是需要先从查询设计加过滤条件、降低分组基数上想办法而不是单纯依赖数据库兜底。FAQQ内存充足的时候数据库还会 OOM 吗A会。内存规划通常按日常查询的峰值估算但大表聚合的中间状态比如多层窗口函数叠加后的物化结果有时会明显超过原始数据量一旦超出规划范围就可能触发 OOM。Q溢写到磁盘和用磁盘临时表硬扛是一回事吗A磁盘临时表是一种常见的内存兜底做法具体覆盖哪些算子各产品不同需要查各自文档。Youngs DB 官网的说法是排序、聚合、去重、JOIN 等算子各自具备溢写能力必须整体驻留的形态超出预算则会报错。Q除了换数据库查询本身能做什么优化A能做的包括加过滤条件缩小扫描范围、用近似算法比如近似去重代替精确计算、减少不必要的排序这些都能直接降低单条查询的内存峰值和数据库层面的溢写机制是互补关系不是替代关系。Q弹性内存自适应是不是意味着内存不用再规划了A不是。它解决的是能溢写的算子在中间状态超出内存时能不能跑完的问题而不是让内存规划变得不重要——机器内存越小越依赖磁盘 I/O查询耗时会相应变长必须整体驻留的形态还会直接受内存预算约束。内存规划仍然影响查询的速度和能否跑完。本文所述能力以云策数据官网与产品文档为准。
返回列表