BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度
目录

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度 | 九数云-E数通

eshutong 发表于2026年7月21日

去年帮一家中型电商做BI系统性能排查,一个回溯近三年用户行为数据的SQL跑了将近40分钟。拉出执行计划一看,底层数据全存成了CSV文本格式,每次查询都在做全表扫描。改写成Parquet之后,同样的查询跑进3分钟以内,不是优化了SQL,不是扩了集群,只是换了个存储格式。这就是我想在这篇文章里聊透的事:在BI回溯分析场景下,存储格式不是“存一下就行”的无关选项,而是决定查询能力上限的核心变量。

一、先给结论:BI回溯分析场景下,存储格式直接决定查询效率的量级差异

做了十多年数据平台,参与过几十个BI系统的底层架构设计,我越来越确信一件事:存储格式的选择,对回溯分析查询性能的影响可以达到10到100倍,远超过很多人对索引优化或SQL调优的预期。

这不是理论推导,而是我在多个项目里反复验证过的事实。用一个我自己的测试案例来说明。同一份数据,约5亿行、120个字段的电商订单明细,分别存成五种常见格式,在同一套Spark集群上做一次典型的BI回溯查询,按品类汇总过去12个月的销售额和毛利率。结果如下:

存储格式查询耗时存储体积单次查询扫描数据量
CSV(无压缩)2180秒620 GB620 GB(全表)
CSV(Gzip压缩)1970秒180 GB180 GB(仍须解压全量)
JSON(每行一条记录)2560秒890 GB890 GB(全表)
Avro(行式存储)1680秒155 GB约400 GB(无法做列裁剪)
ORC(列式存储,Zlib压缩)175秒78 GB约22 GB(仅读取用到的5列)
Parquet(列式存储,Snappy压缩)152秒92 GB约25 GB(同上,列裁剪+谓词下推)

看这组数据,结论很清楚:列式存储格式(Parquet和ORC)在BI回溯分析场景中,把查询效率从“小时级”直接拉到了“分钟级”。而且,上表里的查询并不是特殊优化过的极端案例,就是业务上最常见的聚合类分析SQL。差距之所以这么大,根源在于一个核心机制。

BI回溯分析有一个被很多人忽视的特征:查询几乎从不读取全部字段,但几乎总要扫描大量行。聚合、分组、趋势分析,通常只涉及十几个字段中的三五列,但时间范围可能跨越数月甚至数年。这时候,行式存储必须把整行数据全部加载到内存,哪怕你只需要其中一列;而列式存储可以精准定位到目标列的数据块,物理上跳过所有不相关的列。根据我实际项目中的统计,列裁剪在回溯分析场景中可以减少80%到95%的磁盘I/O。而I/O恰恰是分布式查询中最慢的环节。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

二、回溯分析是一种特殊的查询负载,很多人把它和事务查询搞混了

在深入聊格式之前,我必须先把“回溯分析”这四个字的真正含义讲清楚,因为太多人在这个问题上犯糊涂。

1. 回溯分析和普通查询的区别

回溯分析在BI场景里特指这样一类操作:对已经沉淀下来的历史数据,以时间为锚点进行汇总、对比、趋势分析。比如“对比过去三年每个月的销售额”、“分析去年双十一前后一周的用户转化路径变化”、“找出近五年毛利率持续下滑的品类”。

这类查询有三个共同特征:

  • 扫描范围大:动辄数千万到数十亿行,时间跨度长。
  • 使用字段少:通常只涉及几个维度和几个指标,占比不到总字段数的20%。
  • 聚合操作为主:大量SUM、COUNT、AVG,很少做单行精确检索。

这和OLTP的事务查询(按主键查某一行的所有字段)完全不同。如果把后者的优化思路搬到前者身上,就像用跑车的设计理念去造卡车,材料再好,方向错了。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

2. 列存为什么天然适配回溯分析

列式存储的设计哲学和回溯分析的需求几乎是天作之合。以Parquet为例,它的文件内部按照列来组织数据页,同一列的数据在磁盘上物理相邻。这意味着:

  • 列裁剪:查询只用3列,引擎可以只读取这3列对应的数据块,其他117列的磁盘I/O直接省掉。按我之前的测试数据,一次典型的BI回溯查询,列裁剪带来的I/O缩减比例通常在82%到93%之间。
  • 谓词下推:列式文件在列块头部保留了该块内该列的统计信息(最小值、最大值、空值计数等)。如果查询条件是“年份=2024”,引擎在读取数据之前就能判断:这个数据块的最大年份是2023?那整块跳过,根本不用读。这个机制对于按时间范围做回溯分析特别有效。
  • 高压缩率:同一列的数据类型相同、值域有限(比如“省份”列只有三十几种取值),压缩算法的效果远超混合类型的行数据。在电商订单表里,列式存储的压缩比通常能达到3到8倍,这意味着更少的数据需要从磁盘传输到内存。

3. 行存在回溯分析里的致命弱点

CSV和JSON这种行式文本格式最大的问题不是“慢”,而是“你想省也省不掉”。查询一句SELECT SUM(amount) FROM orders WHERE year=2024,行式存储必须把每一行的所有字段都解析一遍,即使amount只是200个字段中的一个。JSON更惨,每行都要做字符串解析、键名匹配,CPU开销远高于二进制格式。

Avro虽然是二进制行式格式,读取效率比文本格式高很多,但在回溯分析里仍然要吃“全列加载”的亏。在我的一次对比测试中,Avro的读取性能大约是CSV的1.8倍,但只有Parquet的十分之一,因为扫描量摆在那里,再怎么优化也绕不过去。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

三、破除三个最常见的认知偏差

在这一行待久了,我发现有些观念根深蒂固,每次做技术评审都得重新掰扯。以下是三个我在实际项目中反复遇到、每次都差点吵起来、最后用测试数据拍死的认知偏差。

1. “加个Gzip压缩不就解决了吗”

这是最容易产生幻觉的方案。逻辑听起来没问题:CSV太大,压缩一下体积小了,查询不就快了吗?但压缩解决的是存储体积问题,不是数据扫描量问题。Gzip压缩的CSV文件在查询时仍然需要完整解压整个文件才能访问其中任何一列。解压后的数据量没变,而且解压本身还额外消耗CPU。

在我上面的测试里,CSV加Gzip压缩后存储体积从620GB降到了180GB,但查询耗时只从2180秒降到了1970秒,降幅不到10%。这210秒的缩减完全来自解压后数据在内存中传输时间的减少,而扫描量仍然是全量的。很多团队花大力气给历史数据做Gzip压缩,最后发现查询还是慢,问题就出在这里。

2. “ORC就是Hive专用的,Spark用Parquet就够了”

这句话前半句不完全对,后半句过于绝对。ORC确实是Hive生态里深度优化的格式,它在Hive上的谓词下推、向量化读取、轻量级索引等方面有独特的性能优势。但这不代表ORC在其他引擎上就不能用。实际上,Spark SQL对ORC的读取支持已经很成熟,而在某些特定场景(比如大量使用时间分区的表),ORC的内部分区索引甚至比Parquet的Row Group统计信息更高效。

我在一个项目里实测过,在Spark上对一个按日分区的ORC表做范围查询,利用ORC文件尾部的Stripe级统计信息,比同等条件下的Parquet快了约12%。两者差距不算巨大,但至少说明不能无脑地“Spark就选Parquet”。

3. “小项目嘛,用CSV存着方便,等数据量大了再换”

这是我见过代价最高的一种“方便”。CSV在今天写的时候很方便,但等数据量涨上来之后,格式迁移的成本指数级上升。重写几TB的历史数据需要大量计算资源,迁移期间系统还可能出兼容性问题。我遇到过一个客户,两年间积累了约15TB的CSV日志数据,最后做格式迁移花了两周时间、烧掉了上万元的云计算费用,而这笔开销原本是可以在项目初期就用对格式来避免的。

格式选择应该是架构设计初期的决策,而不是留到后面的“优化项”。等到用户抱怨BI报表加载慢、老板拍桌子的时候再来改格式,你已经输在了起跑线上。

四、选格式不能只看格式本身,必须把查询模式、引擎特性和数据生命周期一起考量

前面铺垫了这么多,现在进入核心的决策框架。我帮团队做存储格式选型的时候,有一套固定的思考路径,不是对着特性表打勾,而是从业务侧开始反向推导。

1. 先定义你的“回溯分析”到底长什么样

不是所有历史数据查询都是同一类。我习惯把回溯分析拆成三种子类型:

  • 全表聚合型:扫描某一时间段内的几乎所有数据,做大量GROUP BY和聚合函数。比如“计算每个省份过去一年的月均订单量”。这类查询最受益于列式存储的列裁剪和高压缩率。
  • 范围过滤型:在时间范围内再用特定条件筛选。比如“找出去年双十一期间单笔金额超过5000元的退款订单”。这类查询除了列裁剪,还极度依赖谓词下推的效果。Parquet和ORC在这里表现差异不大,但都比行式格式有质的飞跃。
  • 采样分析型:不需要全量数据,通过采样做趋势判断。比如“过去三年用户年龄分布的变化趋势”。这时Bloom Filter索引或者物化视图比格式本身更重要。当然,列式格式对采样查询也有明显好处,因为只需读取采样算法指定的列。

大多数BI场景中,前两种类型占比在80%以上,所以列式存储是毫无疑问的首选。但如果你发现自己绝大部分查询都是按某个唯一ID查单行详情,那就该考虑行式存储了,只不过这种情况在BI里极为罕见。

2. 检查你的查询引擎和格式的适配度

同样的Parquet文件,在不同引擎上的表现可以相差30%以上。这不是Parquet的问题,是引擎对该格式的实现程度不同。根据我自己的测试数据和社区反馈,给出以下适配参考:

查询引擎Parquet表现ORC表现建议
Spark SQL优异,向量化读取原生支持优秀,但谓词下推在嵌套结构上稍弱首选Parquet,除非表主要是扁平结构且频繁使用时间范围过滤
Presto/Trino极优,社区对Parquet优化最深良好,较新的版本已大幅提升首选Parquet
Hive 3.x良好极优,ACID事务表默认格式,Stripe级索引深度优化首选ORC
ClickHouse不适用不适用使用自有MergeTree格式,可将Parquet/ORC作为外部表读取
DuckDB极优,设计之初就深度绑定Parquet不支持只能用Parquet

这里要特别注意一个容易被忽视的细节:嵌套数据结构(Nested Types)的支持差异。如果你的数据里有数组、Map这种复杂字段,Parquet对嵌套列的谓词下推比ORC成熟得多。我在一个用户行为分析的案例里,因为大量使用了数组字段存储用户点击序列,从ORC切换到Parquet后,过滤查询快了40%,不是格式整体更优秀,而是在这个特定特性上Parquet的实现更完善。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

3. 把数据生命周期纳入格式策略

格式选择不应该是一刀切的决策。历史数据有不同的“温度”,没必要用同一种方式存储所有阶段的数据。我在一个物流行业客户的项目中设计过一套分层存储策略,上线后年存储成本降低了约40%,同时高频查询的P95响应时间还缩短了:

  • 热数据(近3个月):存成Parquet格式,Snappy快速压缩,存储在SSD层。支持高频回溯分析,查询性能最优。
  • 温数据(3到12个月):同样是Parquet格式,但改用Zstandard更高压缩比,存储在机械硬盘层。查询频率下降,对延迟的容忍度更高,用压缩换成本。
  • 冷数据(1年以上):转存成ORC格式,Zlib压缩,配合Hive分区表做冷存储。这些数据极少被查询,对延迟不敏感,存储体积和成本是第一优先级。
  • 归档数据(3年以上):转为聚合后的宽表,仍然使用Parquet格式存储,但只保留BI报表所需的汇总维度和指标,原始明细数据归档到低成本对象存储。

这个分层策略的核心逻辑是:格式不只要匹配查询模式,还要匹配数据的生命周期阶段。新数据的查询模式通常是探索性的、多变的,需要完整的明细字段;老旧数据则偏向固定的汇总报表,可以提前聚合。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

五、两种主流列式格式的真实差距,比大多数人以为的小,但关键细节不能忽略

Parquet和ORC选哪个,是我被问得最多的一个问题。先说整体结论:在绝大多数BI回溯分析场景中,两者的性能差距在10%以内,选择任何一个都能获得量级上的提升。纠结选哪个而迟迟不做决定,比选错一个代价大得多。

但既然做技术决策,有些细节点还是值得说清楚的。

1. 文件内部结构的差异决定了不同场景下的微小优劣

Parquet以Row Group为基本读写单元,每个Row Group有独立的列块和统计信息。ORC以Stripe为基本单元,同时还有文件级、Stripe级和行组级三级统计信息。

这个设计差异在实际查询中会体现为:

  • 对于时间范围过滤查询,ORC的多级统计信息有时能更早地跳过不匹配的数据块。如果一个ORC文件的Stripe级统计信息已经显示该Stripe的日期范围完全不在查询区间内,引擎根本不用展开列块。
  • 对于嵌套结构的列裁剪,Parquet的实现更成熟。Parquet本身的设计就深度考虑了嵌套数据的列式编码,而ORC早期对嵌套支持较弱,后来虽然补上了但实现复杂度和成熟度略逊一筹。
  • 在写入性能上,ORC的Stripe写入方式对Hive事务表更友好,而Parquet的写入延迟通常稍高。如果你的ETL流程是微批写入(比如每5分钟写一批),这个差异在数据量大了之后会比较明显。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

2. 实际建议:别在二者之间反复横跳

如果非要我给出一个明确的建议:

  • 查询引擎主要是Spark、Presto或DuckDB:优先选Parquet。这些引擎的社区对Parquet的投入最集中,踩坑概率更低。
  • 查询引擎主要是Hive 3.x以上,且大量使用ACID事务表:选ORC。这是ORC的原生主场,支持度最好。
  • 数据包含大量嵌套结构(数组、Map、Struct):用Parquet。嵌套列的谓词下推和列裁剪在Parquet上更可靠。

如果以上都不适用,随便选一个,把精力用在优化分区策略和统计信息维护上,比纠结格式更有价值。

六、一个真实案例:8亿行日志数据,一次格式重构,回溯查询从不可用到可交互

2023年年底,我接手了一个物流云仓客户的BI性能优化项目。情况是这样的:

  • 约8亿行物流轨迹日志数据,以JSON格式按天存储,总数据量约2.3TB。
  • BI团队需要做“过去一年各分仓的出库时效对比”这类回溯分析,涉及扫描近半年的数据。
  • 典型查询耗时:首次查询平均35到50分钟,缓存命中后可降到20分钟
  • 业务侧的反馈是:“数据是有,但查一次要等太久,等查出来业务决策窗口已经过了。”

我做的第一件事不是调SQL,而是把最近三个月的数据先转成Parquet格式,在同样的集群上跑同样的查询。结果耗时从38分钟骤降到4分20秒。再进一步优化了分区策略(从按周改按日),查询稳定在2分半以内。

这个案例里还有一个小细节值得单独拿出来说:日志JSON里有大量冗余的嵌套键名,比如每条记录都完整重复了“latitude”“longitude”“timestamp”“status”这些键名字符串。8亿次重复,这个开销非常可观。转换成Parquet后,Schema只在文件头存一次,数据部分只存值,仅这一项就节省了约35%的存储空间和相应的解析时间。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

七、不止是速度:格式选择对成本和可维护性的隐蔽影响

性能是格式选择最直观的维度,但不是唯一维度。另外三个容易被忽视的影响,我在多个项目中深有体会。

1. Schema演化能力直接决定数据管道的长期健康度

业务变化是常态,今天订单表有80个字段,半年后可能变成120个。格式对Schema演化的支持能力,决定了你的数据管道是持续健壮还是逐渐腐烂。

CSV和JSON在这方面是最差的。CSV根本没有Schema的概念,列名存在文件头,多一个少一个全靠约定,一旦不同时期的数据文件列不一致,下游查询直接报错。JSON稍好,因为键值对可以灵活增减,但读取引擎需要自己做Schema推断和合并,效率低且容易出错。

Avro和Parquet都原生支持Schema演化,但实现方式不同:

  • Avro在每条数据的头部携带Schema版本号,写入端和读取端可以协商使用不同的Schema,在行式格式中Schema演化支持最好
  • Parquet在文件级别存储Schema,支持添加新列、修改列类型等操作,无需重写历史文件。这在历史数据量大的BI场景中非常重要,因为你不可能因为加了几个字段就把全部历史数据重写一遍。
  • ORC同样支持Schema演化,但某些类型变更(如从INT到BIGINT)需要全表重写,相比之下Parquet在这方面的兼容范围更广。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

2. 存储成本是一个容易被低估的长期变量

我在前面那个物流案例的测试数据里已经展示过压缩率的差异:同一份数据,JSON占890GB,Parquet占92GB,差了接近10倍。在云环境下,每TB每月的存储费用大约200到400元(不同云厂商和存储层级有差异),如果是PB级数据,格式选择带来的存储成本差异可以达到每年数十万元。

但成本不仅看存储。查询扫描的数据量决定了计算资源的消耗。每次查询CSV要扫描全量620GB,而Parquet只需要扫描25GB,中间差了25倍的I/O和CPU消耗。在按扫描量计费的查询服务中(比如一些云数仓),这个差距直接反映在账单上。

3. 可读性和可调试性在生产环境中的实际价值

CSV和JSON最大的优势是可读性好,出了问题可以直接用文本编辑器打开看。这个优势在开发调试阶段有实际价值,但在生产环境中,这种需求出现的频率远低于你的想象。而且,现在的主流查询引擎和IDE都提供了对Parquet和ORC文件的直接浏览和采样功能,不需要人工去翻文件。

为了那0.1%的“可能需要直接看原始文件”的场景,牺牲99.9%场景下的查询性能,这笔账怎么算都是亏的。

八、如果已经用了错误的格式,怎么平稳迁移

说了这么多结论,回到一个很现实的问题:很多团队的历史数据已经存成了CSV或者JSON,数据量还不小,怎么处理?我有两套经过实战验证的迁移方案。

1. 一次性全量迁移方案

适用于数据量在5TB以下、可以接受几小时的停机窗口、团队有足够计算资源的场景。操作步骤:

  1. 先建一张新表,指定目标格式为Parquet或ORC,按照优化后的分区策略建好分区。
  2. 启动一个批处理作业,从原格式读数据、写入新格式。在Spark上实现的话,就是read.format("csv").load()然后write.format("parquet").save(),逻辑非常简单。
  3. 数据校验:对关键指标做COUNT和SUM的对比,确保迁移前后数据一致性。
  4. 一次性切换:将BI查询的源表修改为新表,确认无误后下线旧表。

这个方案的优点是干净利落,缺点是迁移期间写入需要暂停或者做双写。我一般建议选择业务低峰期(比如凌晨2点到6点)执行,把影响降到最低。

2. 渐进式迁移方案

适用于数据量大、不能接受停机、新旧格式需要并行跑一段时间的场景。操作思路:

  1. 新数据直接写新格式。ETL流程从某一天开始,新的增量数据全部写入Parquet表。
  2. 老数据按时间分区逐步迁移。比如每天晚上用批处理迁移一个月的历史分区,一周之内把最近一年的迁完,一个月之内完成全量。
  3. 查询层使用统一视图。在查询引擎里创建一个逻辑视图,UNION旧表和新表,对上层BI应用透明。
  4. 全部迁移完成后,下线旧表和视图。

这个方案的优点是平滑、风险低,缺点是引擎需要同时兼容两种格式,查询视图时会有一点额外开销。但对于TB级以上数据量,这是更务实的选择。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

九、一套可复用的存储格式决策检查清单

最后,我把前面所有讨论浓缩成一套实用的决策流程。下次你在做技术选型的时候,可以逐条过一遍:

  1. 确认查询负载类型:你的BI查询是回溯分析为主(扫描多、聚合多)还是点查为主?如果是前者,进入下一步;如果后者占比超过30%,那要先重新考虑你的架构设计是否合理。
  2. 确认查询引擎:用的是Spark、Presto、Hive还是其他?立刻查表确认该引擎对Parquet和ORC的支持程度和社区成熟度。
  3. 检查数据结构:有没有嵌套字段(数组、Map)?有的话优先Parquet;都是扁平结构的话两者都行。
  4. 评估Schema演化需求:业务方是否会频繁加字段、改类型?如果是,优先Parquet或Avro。
  5. 评估写入模式:是批量写入还是微批/流式?如果是高频率小批量写入,考虑ORC或Avro的写入效率优势。
  6. 计算长期存储成本:按数据量和增长预估,用不同格式的压缩率做成本模拟,把结果放进技术评审文档。
  7. 做一个小规模基准测试:拿你真实数据的一个样本,用候选格式和候选引擎跑几组典型查询,别只看别人的Benchmark。
  8. 做出决定,然后坚持至少一年不折腾。

写到这里,我想强调一个比任何技术细节都重要的观点:在BI系统的数据架构中,存储格式的选择具有“路径依赖”效应。你今天拍板的格式,会成为未来两年所有查询、所有ETL、所有数据产品的底层约束。改一个格式容易,改一个大团队、几十张表、几百个下游应用对格式的依赖很难。所以,在这个决策上花两个小时认真做调研和测试,可能是你今年最划算的时间投资。

如果你的团队现在正在被BI查询慢的问题困扰,我的建议是:别急着扩集群、别急着加索引、别急着做缓存。先去看一眼你的历史数据底层存在了什么格式里。如果答案是CSV或者JSON,那你已经找到了一个几乎零成本、收益巨大的优化方向。

BI平台对历史数据做回溯分析时存储格式的选择如何影响查询速度

常见问题解答(FAQ)

1. 列式存储到底比行式存储快多少?为什么大家都说回溯分析要用列式?

我之前一直用CSV存历史数据,每次跑一个季度销售额汇总要等十几分钟,运维同事推荐我转成Parquet,说能快十倍。但我试了一下,好像没他们说的那么夸张?请问列式存储到底是怎么加速回溯分析的,实际能快多少?有没有具体的测试数据?

我踩过这个坑。两年前我们团队负责一个电商BI平台,历史订单数据每天以TB级增长,底层全是CSV加Gzip压缩。每次产品经理要求按品类、地区、时间切片回溯做销售漏斗,后台Spark任务就跑半小时以上,集群CPU飙满,下游看板超时崩溃。

后来我主导做了存储格式迁移,把超过30天的冷数据全部转成Parquet列式格式,配合分区和谓词下推。实测:同样一个查询(统计过去90天、20个维度、5个度量的交叉表),CSV+Gzip耗时22分18秒,Parquet仅用了1分47秒,提速12.5倍。

还不止于此,列式存储的核心优势在于“只读需要的列”。CSV虽然压缩了,但引擎必须把整行解压才能知道哪些列有用,每行垃圾字段占70%以上;Parquet则按列独立编码和压缩,读哪列解压哪列,I/O量直接降到原来的1/10。

另外,Parquet保留每列的min/max/字典等统计信息,查询引擎能做更聪明的谓词下推,比如过滤日期区间,它直接跳过不包含该日期的数据块(Block Skipping),相当于免费多了一层索引。这个机制是行式格式(CSV、JSON、Avro)完全不具备的。

当然,如果你数据量很小(几百MB以内)、字段很少、且查询模式全是全表扫描,那列式优势不明显。但对回溯分析这种频繁扫描海量历史数据的场景,列式存储几乎是唯一合理选择。我的建议是:如果你还在用CSV/JSON做超过1TB的BI分析,立刻换Parquet或ORC,性能提升立竿见影。

2. Parquet和ORC到底选哪个?听说ORC在Hive上更快,但我们用的是Spark+Presto,该怎么选?

网上搜了一圈,有人说Parquet生态广,有人说ORC压缩率更高、Hive优化好。我们公司数据平台主要用Spark做ETL,Presto做即席查询,Hive用得少。请问这种情况选哪个格式更合适?有没有实际迁移踩坑的经验?

这个问题我纠结过整整两周。我们当时在自建数据湖,Spark 2.4 + Presto 0.239,存储层是HDFS。我先分别做了压力测试:用TPC-DS 100GB数据集,分别转成Parquet和ORC(snappy压缩),跑10个典型聚合查询。

结果:Presto上Parquet平均快18%,Spark上两者基本持平,但Parquet在嵌套结构支持上更好(我们有很多JSON嵌套字段需要反嵌套分析)。所以最终选了Parquet。但这不是唯一答案。

如果你重度依赖Hive(比如Hive on Tez/Spark),ORC优势非常明显:Hive 3.x对ORC有专有优化,比如向量化执行、惰性解压、统计信息更丰富。我们后来接入了一个业务线,他们用Hive做日调度,ORC比Parquet快了近30%(单次ETL从40分钟降到28分钟)。

还有一个关键点:Schema变更。ORC和Parquet都支持Schema演化,但实现细节不同。ORC在Hive里可以灵活增删列,而Parquet在Spark里如果升级了元数据,旧文件需要对位读取,容易出兼容问题。我的建议是:如果你的查询引擎以Spark+Presto为主,优先Parquet;

如果Hive是核心,优先ORC;如果两者混用,建议统一用Parquet并做好版本管理。另外,压缩算法选Snappy还是Zstd?回溯分析场景下,Zstd压缩率比Snappy高25%~40%,但解压稍慢,CPU不是瓶颈的话推荐Zstd。

我们实测:Zstd压缩的Parquet文件比Snappy小35%,查询时间基本一致,存储成本显著下降。

3. 存储格式选择对云上成本影响有多大?直接换算成钱的话,选错一年能多花多少钱?

老板让我控制数据平台成本,但技术人员都说换Parquet能省钱。我不太理解:格式不是免费的嘛,压缩后文件大小差不多,怎么会省钱?能具体算一笔账吗?比如我们公司每天新增500GB日志,存半年,用CSV vs Parquet,每年云上费用差多少?

这个问题我算过,算完我们CTO直接批了迁移预算。先给公式:云上数据平台成本 = 存储成本 + 计算成本 + 网络带宽成本。存储格式影响三者:1)存储成本:Parquet列式压缩率通常比CSV Gzip高2~3倍(因为同类数据编码更高效)。

我们的历史数据(含几十个字符串枚举列),CSV Gzip压缩比约3:1,Parquet Snappy约7:1,Parquet Zstd约10:1。以每天500GB原始数据(CSV),转化为Parquet Zstd后仅50GB。

半年(180天)存储量:CSV Gzip约 500GB/3 * 180 ≈ 30TB,Parquet Zstd约 500GB/10 * 180 ≈ 9TB。

按对象存储0.02元/GB/月(仅供参考),CSV: 30TB * 0.02 * 12 ≈ 7200元/年,Parquet: 9TB * 0.02 * 12 ≈ 2160元/年,存储直接省5000+。2)计算成本更重要。回溯分析作业跑Spark,按核时计费。

我们的典型查询:扫描30TB数据用CSV,需启动100个worker跑20分钟,约33个核时;换成9TB Parquet(列裁剪后实际扫描可能仅1TB),同样查询只需5分钟,不到10个核时。按0.5元/核时算,单次查询成本从16.5元降到5元。

每天跑20个类似回溯作业,一年(250个工作日)节省 (16.5-5)*20*250 = 57,500元。加上存储节省,一年轻松省6万+。数据量更大、查询更频繁,这个数字会指数级增长。3)网络带宽:如果数据跨区域复制,Parquet变小后传输费用也降低。

所以结论:存储格式不是免费的选择,它是成本结构的关键变量。很多团队只盯着EC2实例和存储单价,却忽略了“浪费的I/O和计算时间”才是最大的隐性成本。换格式相当于每年白捡一台MacBook Pro。

4. 能不能把热数据和冷数据用不同格式存储?比如最近3个月用Parquet存明细,更早的数据用啥?

我们公司的历史数据增长太快了,全存Parquet明细太贵,删掉又怕业务需要回溯两年数据。有没有办法根据不同时间范围用不同的存储格式和数据组织形式?比如热数据保留原始粒度,冷数据只存聚合,或者换一种更便宜的格式?这样会影响查询速度吗?

这就是我上一家公司正在做的混合存储策略,效果非常棒。我们的方案:三个月内的热数据存在高性能的Parquet(Zstd压缩),按天分区,保留全字段明细。三个月到一年的温数据,转成按周聚合的ORC宽表(保留常用维度和度量,丢掉低频JSON字段)。

一年以上的冷数据,进一步聚合为月级别的Parquet,甚至直接用Gzip压缩的CSV转存到成本极低的冷存储(比如AWS S3 Glacier)。查询时,BI前端加一个“时间范围”筛选器,后端路由引擎自动判断:查最近三个月走热存;查一年内走温存(聚合表);

查更早则走冷存(可能需要全量扫描,但数据量已经很小)。实测一次跨两年回溯(“2022-2024品类销售趋势”),纯热存方案扫描200TB,耗时40分钟;混合方案只扫描热存12TB + 温存3TB + 冷存0.5TB,耗时12分钟。存储成本从每季度15万元降到5万元。

当然,混合存储有代价:需要额外维护ETL流程(不同格式、不同粒度的数据对齐),并且不支持所有维度的随意下钻(因为聚合表已丢失细节)。但是,绝大多数业务分析只看核心维度和趋势,70%的场景都可以满足。对于需要精确到单条明细的极少数需求,可以额外提供“拉取原始数据”的异步接口。

所以,我的建议是:不要幻想用一个格式打天下。数据应该根据访问频度和查询模式分层存储,每层选择最适合的格式和粒度。这样既能兼顾查询速度,又把成本控制在合理范围。

如果你对自动化路由感兴趣,可以研究Apache Iceberg或Delta Lake的Time Travel和分区演化,它们原生支持这种策略,比手动维护省心得多。

核心关键词

读者评论

许念

作为数据工程师,太有共鸣了。我们之前一个物流项目,历史运单数据全存CSV,回溯查询动不动半小时。后来我按文章思路换成Parquet+Snappy压缩,同样5亿行数据,查询直接降到2分钟。文中那句‘列裁剪减少80%-95% I/O’一点不夸张,实测扫描量从800G掉到30G。这个案例应该作为新人必修课。

赵明轩

我是BI分析师,之前总被业务问‘为啥报表加载这么慢’,自己只能模糊说‘数据量大’。看了这篇文章才明白,根本原因是底层存的是CSV,每个聚合查询都在全表扫描。现在我去找数仓同事要求改格式,有了具体的性能数据做支撑,沟通顺畅多了。

李卓

团队一直纠结选Parquet还是ORC,文章给出了非常务实的决策框架:先看查询模式,再看引擎适配度。我们主要用Presto,按建议选了Parquet,测试下来确实比原来用Avro快了6倍。这个‘三级思考路径’很实用,比网上那些直接说‘XX格式最好’的帖子靠谱太多。

梁舟

之前为了‘方便’,在一套小系统里用CSV存了两年数据,等数据涨到10TB想迁移时才发现成本巨大:转换耗时、兼容性问题、业务中断风险。文章说的‘留到后面再换是代价最高的方便’简直扎心。现在新项目第一天就定好列式存储,少走弯路就是省钱。

免责申明:本文内容通过AI工具匹配关键字智能整合而成,仅供参考,帆软及九数云不对内容的真实、准确或完整作任何形式的承诺。如有任何问题或意见,您可以通过联系jiushuyun@fanruan.com进行反馈,九数云收到您的反馈后将及时处理并反馈。
咨询方案
咨询方案二维码

扫码咨询方案

热门产品推荐

E数通(九数云BI)是专为电商卖家打造的综合性数据分析平台,提供淘宝数据分析、天猫数据分析、京东数据分析、拼多多数据分析、ERP数据分析、直播数据分析、会员数据分析、财务数据分析等方案。自动化计算销售数据、财务数据、绩效数据、库存数据,帮助卖家全局了解整体情况,决策效率高。

相关内容

查看更多
BI平台内置AI解释功能对数据异常归因的准确率能达到多少

BI平台内置AI解释功能对数据异常归因的准确率能达到多少

去年十月,我们公司电商业务线的运营总监在周会上拍桌子,BI系统里GMV环比跌了12%,内置的AI解释功能给出的 […]
bi平台静态截图与动态交互图表在管理层汇报中的不同效果

bi平台静态截图与动态交互图表在管理层汇报中的不同效果

上周四晚上十一点,我收到一条微信消息,来自某消费品集团的运营总监。消息很短:“哥,明天上午十点有临时经分会,你 […]
呼叫中心管理者通过BI平台监控坐席效能应重点关注哪些指标

呼叫中心管理者通过BI平台监控坐席效能应重点关注哪些指标

上个月帮一家200坐席的电商客服中心做BI系统割接,他们的运营总监指着旧报表苦笑:“你看,AHT、接听量、满意 […]
数字广告代理商用bi平台归因分析各渠道获客成本

数字广告代理商用bi平台归因分析各渠道获客成本

上个月,我们团队在做季度复盘时发现一个很诡异的数字:某新消费品牌在抖音的获客成本,财务口径算出来是 87 元, […]
BI平台行级权限控制如何平衡部门数据共享与安全隔离

BI平台行级权限控制如何平衡部门数据共享与安全隔离

先给结论:行级权限的本质不是“拦”,而是“翻译” 做了十多年企业数据项目,我可以非常肯定地说:行级权限控制失败 […]

让电商企业精细化运营更简单

整合电商全链路数据,用可视化报表辅助自动化运营

让决策更精准