Row vs columnar at system scale
Problem
The same organization often runs:
- Services exchanging whole records (user profile, order command, device event).
- Analytics scanning billions of rows but only a few columns (revenue by day, feature columns for training).
Teams collapse both onto one encodingââeverything is Protobufâ or âeverything is Parquetââand pay either impossible scan costs or impossible per-message overhead. The 101 axis row vs columnar becomes a system boundary question at 301 scale.
Short answer
Use row-oriented messages (JSON objects, Protobuf messages, Avro records, MessagePack maps) when the unit of work is whole records with low-latency point access or per-event processing. Use columnar layouts (Parquet, ORC, Arrow tables) when the unit of work is bulk scan/aggregate over few columns on large datasets. Crossing the streams is occasional glue (export jobs), not a default architecture. Do not pick columnar because it compresses well in a blog chart if every request needs the full row in under a millisecond.
Assumes 101 row/columnar axis; this page owns workload architecture.
Constraints that matter
| Axis | Row-oriented messages | Columnar tables / files |
|---|---|---|
| Access | Get one entity; process one event | Scan column subsets over partitions |
| I/O shape | Whole record contiguous | Column chunks; predicate pushdown |
| Latency | Often ”sâms per message | Throughput-oriented batch/stream jobs |
| Evolution | Per-message schema/IDL culture | Table schema + file footers + catalog |
| Compression | Per message or stream framing | Column stats, dictionary, page compression |
| Typical home | API, RPC, queues, OLTP-style paths | Lakes, warehouses, feature stores, ML batch |
Decision frame
| Workload | Default encoding class | Poor default |
|---|---|---|
| Public or internal RPC | Row (JSON / schema-driven / schemaless binary) | Parquet files per request |
| Kafka-style event processing (per event) | Row (Avro/Protobuf/JSON) | Columnar unless micro-batch deliberately |
| Nightly lake on object storage | Columnar (Parquet/ORC) | Millions of tiny Protobuf files as the lake |
| Interactive notebook on large tables | Arrow / columnar engines | Nested JSON lines as sole store |
| Feature training over wide tables | Columnar | Row RPC dumps without projection |
| Cache get-by-id | Row | Columnar file open per key |
Do we mostly read ALL fields of FEW records?
yes â row-oriented message codecs
Do we mostly read FEW fields of MANY records?
yes â columnar storage / Arrow-class interchange
Failure modes
| Mistake | Consequence |
|---|---|
| Protobuf lake | Tiny files, no column prune, ops nightmare |
| Parquet RPC | Catastrophic per-call overhead; wrong mutability story |
| One format to rule them all | Either analytics or services becomes second-class |
| Ignoring partition design | Columnar without partition/predicate strategy still scans the world |
| Confusing Arrow with Parquet | Arrow â in-memory/interchange; Parquet â on-disk columnarârelated, not identical jobs |
Real-world sketch
A metrics pipeline ingests events as Protobuf (good: row, low latency). Analysts dump the same Protobuf messages as the lake format. Queries that need two fields open every message fully. Moving the serving path to remain Protobuf while a batch compact job writes Parquet partitions by day cuts scan cost without changing the real-time contract. The suite may show excellent Protobuf decode rates; that does not make Protobuf a lake format.
In this suite
| Resource | Role |
|---|---|
| Language harnesses | Predominantly row-oriented message codecs and fixtures |
| Test Data | Record-shaped fixtures (message, document, telemetry, âŠ) |
| Serialization categories | Families for message codecsânot a Parquet engine benchmark |
| Using this suite | How to read message-level Results |
Important: this suite is not a columnar engine benchmark. Absence of Parquet/Arrow from a language Results page means ânot measured here,â not âirrelevant for lakes.â
Experiments
Question: Is this path row/RPC-shaped or analytical/columnar, and are we using the wrong codec class for the system?
Setup
- Describe access pattern: point lookups / RPC vs scan aggregates over many rows.
- Estimate selectivity (few columns vs wide rows) and data volume.
- Candidate stacks: row JSON/Protobuf/Avro vs Parquet/ORC/Arrow-class.
Procedure
- Classify primary workload using the decision frame.
- If analytical: prototype scan time and compression on columnar layout vs dumping RPC rows.
- If RPC: measure per-message latency with row codecs; do not use lake formats on the hot path.
- Suite Results orient row codec costs onlyâdo not treat them as lake rankings.
- Document two-hop design if both patterns exist (events row â lake columnar).
Decision rule
- Scan-heavy lake path â columnar system format; RPC suite winners are irrelevant.
- Hot RPC â row/schema-driven family; columnar files are not substitutes.
Metrics
| Metric / signal | Role |
|---|---|
| Query shape (point vs scan; columns touched) | Primary classifier |
| Scan time / bytes read for analytical job | Columnar effectiveness |
| RPC p99 per message | Row-path SLO |
| Compression ratio on lake files | Storage economics |
Suite total_median_ns / median_size_bytes |
Row-codec orientation only |
| Cross-paradigm âwinnerâ charts | Misleading for this decision |
Conclusion style: âIngest RPC uses Protobuf rows; lake uses Parquet; no dual-use of one codec.â
What this suite cannot tell you
- Scan cost of Parquet vs ORC on your warehouse.
- Arrow zero-copy handoff between two specific engines.
- Optimal partition/layout for your lake.
- Whether micro-batch columnar encoding of events is worth the complexity.
Common mistakes
- Citing message-codec Results to justify lake format choice.
- Forcing analytics to query an operational RPC log format forever.
- Using columnar âbecause compressionâ on chatty ultra-small RPCs.
Key takeaways
- Access pattern chooses row vs columnar more than fashion.
- Services â row messages; lakes/analytics â columnar (with deliberate bridges).
- Suite Results inform message codec choice inside a languageânot lake architecture.
- Dual paths (row for serve, columnar for analyze) are normal, not failure.