Build1 distinct publisher3 min readUpdated
A 5-million-row file, opened byte by byte, puts the credit where it belongs: column locality, neighbour-dependent encoding, and metadata you can skip.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
A developer wrote a small ORC parser from scratch, generated a deliberately boring 5-million-row orders table, and read the file by hand instead of repeating the usual summary about columnar storage and predicate pushdown [1]. What comes out of the byte-level walk is a reordering of credit: the compression codec only runs after encoding is done, and by then most of the size reduction has already happened [17][21]. Start with the read path. The last byte of an ORC file holds the length of the PostScript, and in this file the final 26 bytes decode as a Protocol Buffers message [7]. That means a query engine performs three reads, the last byte, the PostScript, then the footer plus metadata, totalling a few hundred bytes against a 53 MB file [8]. After those reads it has the schema, the row count, every stripe's byte offset, and min/max statistics for every column, without having touched a row [9]. The ordering is forced rather than clever: the codec name lives in the PostScript, and the PostScript cannot itself be compressed, because you would need the codec to decompress the thing that names the codec [10]. Locality is equally mechanical. Inside a stripe a column is a set of streams laid out contiguously, so the country column appears as 23 bytes of DICTIONARY_DATA, 5 bytes of LENGTH and 310,404 bytes of DATA, while price DATA is 2,374,052 bytes [14]. Reading country from one stripe is a single range read rather than 687,104 scattered seeks [15]. Nullability is priced the same way: the PRESENT stream is omitted entirely when a column has no nulls, so null tracking here cost zero bytes, where a row format pays on every row whether you use it or not [16]. The encoding numbers are the part worth arguing about. Five million sequential 64-bit integers occupy 11 KB, because ORC's RLE v2 picked its DELTA sub-encoding and stored a base, a delta width and a run length [17]. Raw, those values are 40 MB, so the encoder cut roughly 3,600x before zlib was invited in [18]. Sort order is the lever: the same 5 million dates take 7,390,184 bytes in random order and 4,898 bytes sorted, which the author measures as 1,500x [19]. Compression that only works when neighbours are similar means physical row order is a schema decision, not a cosmetic one. Two defaults deserve attention. PyArrow's dictionary_key_size_threshold defaults to 0.0, which disables dictionary encoding outright; setting it to 0.8 was worth 14% of the file from one keyword argument [20][4]. And the codec runs in independent 64 KB chunks with a 3-byte header, where bit 0 marks a chunk as stored raw if compressing it made it bigger, which is also what makes seeking cheap: one large compressed blob would mean inflating 8 MB to read the last value [21][22]. Read the setup before borrowing the conclusions. Stripe size was set to 8 MB on purpose, because production ORC uses 64 to 256 MB stripes and a default stripe would have swallowed this whole 53 MB dataset, leaving nothing to skip [6][4]. The skip machinery is cheap at this scale: 8,412 bytes of index against 8,544,070 bytes of data in stripe 0, which the author puts at 0.1% overhead [12][13], with min/max statistics kept at three zoom levels, 448 bytes for the file, 663 for a stripe, and 8.4 KB per stripe for row groups of 10,000 rows [24]. Uncompressed ORC is still 3.6x smaller than the equivalent 310 MB CSV, a gap the author attributes purely to layout and encoding [23][5]. Worth checking on your own writers: whether dictionary encoding is switched on at all, whether the columns you filter by are the columns you sort by, and whether your stripe size leaves more than one stripe to skip.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The author reduces ORC's speed to three things: store each column's values together so one column can be read without touching others; encode values in ways that only work when neighbours are similar; and keep a small map of what is inside so a query can skip most of the file. Compression codecs, bloom filters and ACID support are built around that core.
Production ORC uses 64-256 MB stripes; because the author's whole file is 53 MB, a default stripe would swallow the entire dataset and leave nothing to skip, so the stripe size was shrunk to make multi-stripe behaviour visible on a laptop.
Five million sequential 64-bit integers occupy 11 KB, because ORC's RLE v2 picks its DELTA sub-encoding and stores a base, a delta width and a run length; zlib never saw 40 MB of integers because the encoder never produced them.
dictionary_key_size_threshold defaults to 0.0, which disables dictionary encoding entirely; the setting is worth 14% of the file from one keyword argument.
ORC keeps min/max statistics at three zoom levels: file (448 bytes), stripe (663 bytes) and row group of 10,000 rows (8.4 KB per stripe).
The author wrote a small ORC parser from scratch, generated 5 million rows in a deliberately boring orders table, and opened the resulting file by hand, rather than accepting the standard explanation of columnar storage, built-in indexes and predicate pushdown.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Specific and internally consistent, but single-source and self-reported
The post supplies unusually concrete artefacts for a blog teardown: a 26-byte hex dump of the file tail, a stripe table with offsets and row counts, per-stream byte counts, the exact PyArrow write call, and a before/after pruning experiment whose arithmetic checks out (2,335,435 of 24,430,256 bytes is the stated 13.7%; 8,412 of 8,544,070 is the stated ~0.1%). Against that, every number comes from one author's hand-written parser on one synthetic dataset with no independent reproduction, and two supporting tables - per-column bytes and the codec comparison - are absent from the supplied text, leaving the zstd and 14% dictionary figures unshown.
No deployment or usage signal in supplied sources
The only observation available is the author's own laptop benchmark on a synthetic file. Nothing in the supplied material reports production deployments, engine integrations in use, release activity, pricing, licensing or usage disclosures for ORC or for the techniques described, so adoption cannot be scored without inventing facts.
Claims run slightly behind the shown measurements
The framing is deliberately deflationary - it attacks the 'columnar, indexes, pushdown' slogan, says credit for size is 'mostly wrong' when given to compression, and calls ORC's statistics a summary rather than an index - and the byte counts shown generally exceed the rhetoric attached to them. That pushes the gap modestly negative. It is not more negative because two assertions outrun their evidence (zstd winning 'on all three axes' with no table, and zlib remaining the default 'because ORC is old'), and because headline ratios such as 3,600x and 1,500x come from an idealised synthetic column set and a deliberately non-production stripe size that will not generalise cleanly.
Individual developer-platform post with reputational, not commercial, stake
The sole source is a first-person technical post on a developer publishing platform, with no vendor, sponsor, product, pricing or hiring pitch anywhere in the supplied text and no commercial interest in ORC disclosed or implied. The residual incentive is the ordinary one for such formats: audience-building through a contrarian 'everyone else just repeats a slogan' framing and eye-catching compression ratios, which favours dramatic single-column results over caveated averages.
Moderate: mechanisms well grounded, magnitudes narrowly sourced
Confidence in the mechanism-level claims - tail metadata bootstrap, contiguous column streams, encode-then-compress ordering, statistics as coarse summaries - is fairly high because they are demonstrated with byte-level detail and are internally consistent. Confidence in the magnitudes is lower: one publisher, one synthetic dataset, one laptop, a deliberately non-production stripe size, no engine timings, and two claims whose backing tables are missing. There is also no adoption evidence to corroborate any of it.
build
Fabric's customer-managed keys now reach Spark shuffle and spill, closing a compliance line item1 distinct publisher
build
Databricks says the hard part of warehouse migration was the stored procedures, not the data1 distinct publisher
build
Iceberg votes to forbid new equality deletes in V4, and Parquet 1.18.0 lands with two corruption bugs1 distinct publisher
product
Cloudera bets the agentic AI bottleneck is where the data sits, not which model runs1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 21, 2026