3. 行式文本格式(CSV/JSON)在逐笔数据中的适用性剖析
在逐笔数据压缩存储的讨论中,CSV 与 JSON 常被当作“基准格式”:它们不依赖专用编解码库,任何语言都能读写,调试时肉眼可读。但“能读”不等于“适合存”。本节以一份真实的逐笔成交样本为对象,量化 CSV 与 JSON 的存储开销、解析效率与查询灵活性,并给出它们作为基准格式的适用边界。
样本与度量口径
取某交易日某只股票连续竞价阶段的逐笔成交样本,字段为:成交编号(seq)、交易所通道号(channel)、证券代码(code)、成交时间(毫秒时间戳,time)、成交价格(price,单位0.01元)、成交数量(qty,单位股)、买卖方向(bs,B/S)、买方委托序号(bid_seq)、卖方委托序号(ask_seq)。样本共 100 万行,价格区间 10.00~10.99 元,单笔数量 100~5000 股,委托序号为 8 位整数。
度量口径需先固定,否则比较没有意义:存储开销按“未压缩原始字节数”和“gzip -6 压缩后字节数”两档统计;解析效率按单线程逐行解析并累加成交金额的总耗时计;查询灵活性按“按时间区间过滤”“按买卖方向聚合”“按委托序号反查”三类典型查询的实现难度与是否需要全表扫描来评价。以下数值为教学示例中的合理估算,用于说明量级关系,不代表特定硬件上的实测结果。
存储开销:文本的“体积税”
CSV 每行形如 1000001,7,600000,34200123,1050,300,B,88123456,88234567,平均约 62 字节;100 万行约 62 MB。JSON 若采用“每行一个对象”的 JSON Lines 形式,键名重复出现,单行膨胀到约 150 字节,总量约 150 MB;若改为“一个数组包全部对象”,键名只出现一次,但仍需逗号、引号与括号,约 95 MB。作为对照,同样字段用二进制定长结构存储约 33 MB,用列式加字典编码可压到 8 MB 量级。
更关键的是压缩后的表现。CSV 经 gzip 压缩约降至 18 MB,压缩比约 3.4:1;JSON Lines 压缩后约 22 MB,压缩比虽高(约 6.8:1),但绝对体积仍大于 CSV。原因在于文本中大量重复的键名和分隔符恰好是压缩算法的“好素材”,压缩能吃掉一部分冗余,却吃不掉数字被展开成 ASCII 字符带来的根本膨胀——一个 4 字节整数写成十进制文本要 8~10 字节,价格 1050 本可 2 字节存储却占了 4 个字符。
解析效率:字符到数值的转换成本
CSV 解析的典型路径是:按分隔符切分、逐字段做字符串到数值的转换(strtol/strtod)、组装结构体。JSON 解析则要先做词法分析识别引号与括号,再按键名查表映射到字段,最后同样做数值转换。两者都绕不开“ASCII 数字 → 二进制数值”这一步,而这一步正是逐笔数据解析的主要开销:100 万行、每行 6 个数值字段,就是 600 万次字符串转换。
在示例估算中,CSV 单线程解析 100 万行约需 1.2 秒,JSON Lines 约需 3.5 秒,JSON 数组因需整体构建对象树约需 4.2 秒;而二进制定长格式按结构体直接映射,约 0.15 秒。差距来自两处:一是 JSON 的键名匹配与对象分配,二是文本格式无法做零拷贝的批量读取。对回测、实时风控这类需要反复加载全量逐笔数据的场景,解析耗时会被放大到不可忽视的程度。
查询灵活性:文本格式的真正优势
CSV 与 JSON 的强项不在存储和解析,而在“无需预定义模式即可查询”。用 awk -F, '$5>=1050 && $7=="B"' 就能筛出价格不低于 10.50 元的主动买成交;用 jq 'select(.bs=="B") | .qty' 可直接对 JSON 做方向过滤与字段投影。这类临时性、探索性查询不需要建表、不需要写导入脚本,对数据探查和问题定位极有价值。
但要注意其代价:上述查询都是全表扫描,无法利用时间或委托序号做索引下推;按委托序号反查需要遍历全部行;按方向聚合也要读完整份文件。文本格式的“灵活”是表达上的灵活,不是执行上的高效。若把逐笔数据长期以 CSV 存放并频繁做区间查询,扫描成本会随数据量线性增长。
作为基准格式的优缺点与适用边界
综合来看,CSV/JSON 作为基准格式的优点明确:跨语言、可读、可用通用工具直接处理、便于人工核对与样本交换、无需维护模式版本。缺点同样明确:体积膨胀数倍、解析需字符转换、缺乏索引与类型信息、浮点与整数精度依赖解析器实现、字段顺序或键名变更缺乏约束。
因此适用边界可以这样划定:适合作为小样本交换格式、调试与人工核查格式、数据探查与一次性分析格式、以及压缩方案对比时的“基线”;不适合作为逐笔数据的长期主存储、高频回放数据源或需要低延迟随机查询的在线存储。工程上的常见做法是“双轨”:主存储用二进制或列式压缩格式承载全量历史,同时保留按日或按样本裁剪的 CSV/JSON 导出,供排查与交付使用。
一个可复用的对比记录模板
做格式选型时,建议把比较结论固化成可复核的记录,而不是停留在印象。下表字段可直接用于本节样本或自有样本的对比归档:
| 度量项 | 记录内容 | 本节示例值 |
|---|---|---|
| 样本规模 | 行数、字段数、时间跨度 | 100 万行 / 9 字段 / 连续竞价 4 小时 |
| 原始体积 | 未压缩字节数 | CSV 62 MB;JSON Lines 150 MB |
| 压缩体积 | gzip -6 后字节数及压缩比 | CSV 18 MB(3.4:1);JSON 22 MB(6.8:1) |
| 解析耗时 | 单线程全量解析并累加金额 | CSV 1.2 s;JSON Lines 3.5 s |
| 典型查询 | 时间区间、方向聚合、序号反查 | 均需全表扫描,无索引下推 |
| 结论 | 是否作为主存储 / 仅作交换与基线 | 仅作交换、调试与压缩基线 |
把这张表填完,格式选择就不再是“习惯问题”,而是有数据支撑的工程判断。CSV 与 JSON 的价值在于降低理解与交换的门槛,它们的边界则在于体积、解析与查询效率——认清这条边界,才能让后续的二进制与列式压缩方案有的放矢。