<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BigdataSight</title>
    <description>The latest articles on DEV Community by BigdataSight (bigdatasight).</description>
    <link>https://dev.to/bigdatasight</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14196%2F0292ee02-67c6-4346-9f38-675c204b837c.png</url>
      <title>DEV Community: BigdataSight</title>
      <link>https://dev.to/bigdatasight</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bigdatasight"/>
    <language>en</language>
    <item>
      <title>The query succeeded. Which table state did it read?</title>
      <dc:creator>Rui Wang</dc:creator>
      <pubDate>Thu, 30 Jul 2026 02:31:28 +0000</pubDate>
      <link>https://dev.to/bigdatasight/the-query-succeeded-which-table-state-did-it-read-1g7o</link>
      <guid>https://dev.to/bigdatasight/the-query-succeeded-which-table-state-did-it-read-1g7o</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Why two successful queries can count different rows when they resolve different Delta or Iceberg table states.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two queries return different counts for the same Iceberg table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the catalog query returns 12,480,032 rows;&lt;/li&gt;
&lt;li&gt;a direct scan of the storage folder returns 12,691,404 rows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither query fails. The difference is 211,372 rows. The numbers are&lt;br&gt;
fictional, but the investigation problem is real.&lt;/p&gt;

&lt;p&gt;Before comparing SQL engines, compare the inputs. The catalog query and the&lt;br&gt;
folder scan may not have read the same logical table.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lakehouse table is a selection of files
&lt;/h2&gt;

&lt;p&gt;A Delta or Iceberg table may store its rows in Parquet files, but the directory&lt;br&gt;
is not the table definition.&lt;/p&gt;

&lt;p&gt;For Delta, a table version is reconstructed from its transaction log. The log&lt;br&gt;
records which logical files were added or removed. A logical file can also&lt;br&gt;
carry a deletion vector that marks rows as no longer present. A file removed&lt;br&gt;
from the current version may remain in storage until a later cleanup.&lt;/p&gt;

&lt;p&gt;For Iceberg, a catalog or table reference points to table metadata. That&lt;br&gt;
metadata identifies a snapshot. The snapshot points to a manifest list, and&lt;br&gt;
the manifests identify the data files and delete files used for the scan.&lt;/p&gt;

&lt;p&gt;This distinction explains why listing every Parquet object can produce a&lt;br&gt;
plausible but incorrect result. The folder may contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;files used by the selected table state;&lt;/li&gt;
&lt;li&gt;files retained for an older state;&lt;/li&gt;
&lt;li&gt;files left by a failed or abandoned write;&lt;/li&gt;
&lt;li&gt;data whose rows are changed by separate delete metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The object listing answers, "What exists at this location?" The table metadata&lt;br&gt;
answers, "What belongs to this version or snapshot?" An investigation often&lt;br&gt;
needs both answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work from the selected state outward
&lt;/h2&gt;

&lt;p&gt;Suppose an Iceberg snapshot references 118 data files and 2 delete files. The&lt;br&gt;
storage prefix contains 126 Parquet objects.&lt;/p&gt;

&lt;p&gt;Scanning all 126 objects does not prove that the snapshot is wrong. Some&lt;br&gt;
objects may belong to an older snapshot or to no committed snapshot. Ignoring&lt;br&gt;
the 2 delete files can also count rows that the table considers deleted.&lt;/p&gt;

&lt;p&gt;Start with the reference the user selected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Record the catalog, branch, tag, version, timestamp, or other table
reference used by the query.&lt;/li&gt;
&lt;li&gt;Resolve it to an exact Delta version or Iceberg snapshot ID.&lt;/li&gt;
&lt;li&gt;Follow the metadata chain and construct the active data-file and delete-file
sets.&lt;/li&gt;
&lt;li&gt;Check whether each referenced object is accessible. If the metadata records
a length or another identity that can be checked safely, compare that too.&lt;/li&gt;
&lt;li&gt;Apply the format's delete semantics before comparing row counts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not begin with the newest-looking metadata filename. In Iceberg, the catalog&lt;br&gt;
or table reference chooses the current metadata. In Delta, the selected log&lt;br&gt;
version and its preceding state determine the snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing and extra files mean different things
&lt;/h2&gt;

&lt;p&gt;A referenced file that the reader cannot access makes the check incomplete.&lt;br&gt;
That observation alone does not distinguish a missing object from a temporary&lt;br&gt;
service or authorization failure.&lt;/p&gt;

&lt;p&gt;In Apache Iceberg issue 4168, a user reported a data-file upload failure&lt;br&gt;
followed by a manifest that still referenced the object. A later query failed&lt;br&gt;
when it needed that file. This is an example of the failure shape, not proof&lt;br&gt;
that every inaccessible reference has the same cause.&lt;/p&gt;

&lt;p&gt;The safe result is &lt;code&gt;incomplete&lt;/code&gt;. Treating an unreadable reference as zero rows&lt;br&gt;
would turn missing evidence into a clean-looking count.&lt;/p&gt;

&lt;p&gt;An unreferenced object needs a different interpretation. It might be retained&lt;br&gt;
for an older snapshot, left by an unsuccessful write, or waiting for approved&lt;br&gt;
maintenance. Its presence alone does not prove corruption, and deleting it&lt;br&gt;
during an investigation could damage a state that another reader still needs.&lt;/p&gt;

&lt;p&gt;Keep the first check read-only. Determine whether any committed state still&lt;br&gt;
references the object before considering cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  A successful query is one piece of evidence
&lt;/h2&gt;

&lt;p&gt;A successful query tells you that an engine returned rows. Record the exact&lt;br&gt;
table state separately before deciding what the result proves. The result does&lt;br&gt;
not, by itself, establish that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the query selected the state the user intended;&lt;/li&gt;
&lt;li&gt;every metadata reference and object was present;&lt;/li&gt;
&lt;li&gt;the reader understood every required table feature and delete type;&lt;/li&gt;
&lt;li&gt;another engine resolved the same catalog reference and cached metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When two results disagree, save the selected version or snapshot, active-file&lt;br&gt;
counts, delete-file counts, and unsupported features before rerunning either&lt;br&gt;
query. A rerun against a newer state can erase the comparison you needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small evidence record
&lt;/h2&gt;

&lt;p&gt;The record does not need every metadata field. It needs enough information for&lt;br&gt;
another engineer to repeat the decision.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Question&lt;/td&gt;
&lt;td&gt;Why do the catalog query and folder scan differ by 211,372 rows?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selected state&lt;/td&gt;
&lt;td&gt;Iceberg snapshot 711.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metadata check&lt;/td&gt;
&lt;td&gt;Snapshot and manifest chain resolved.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File check&lt;/td&gt;
&lt;td&gt;118 referenced data files present; 8 additional objects not attributed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete check&lt;/td&gt;
&lt;td&gt;2 delete files apply to the selected snapshot.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result&lt;/td&gt;
&lt;td&gt;Incomplete until the folder scan applies the same active-file and delete rules.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do not include credentials, signed URLs, private paths, SQL, schemas, customer&lt;br&gt;
information, or raw provider errors in the record.&lt;/p&gt;

&lt;p&gt;The two inputs are now specific: snapshot 711, interpreted through its data and&lt;br&gt;
delete manifests, and a scan of 126 physical objects. Make the folder scan use&lt;br&gt;
the same active-file and delete rules, then recount. That check can explain the&lt;br&gt;
211,372-row difference instead of running two vague queries again.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/delta-io/delta/blob/master/PROTOCOL.md" rel="noopener noreferrer"&gt;Delta Transaction Log Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://iceberg.apache.org/spec/#snapshots" rel="noopener noreferrer"&gt;Apache Iceberg specification: snapshots and manifests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apache/iceberg/issues/4168" rel="noopener noreferrer"&gt;Apache Iceberg issue 4168: a referenced data file was unavailable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One question for Delta and Iceberg users
&lt;/h2&gt;

&lt;p&gt;When a table's state looks wrong, which step usually costs you the most time?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identifying the exact version or snapshot&lt;/li&gt;
&lt;li&gt;Following the metadata chain&lt;/li&gt;
&lt;li&gt;Matching referenced files to object storage&lt;/li&gt;
&lt;li&gt;Understanding delete files or deletion vectors&lt;/li&gt;
&lt;li&gt;Reproducing the same result in another tool&lt;/li&gt;
&lt;li&gt;Something else&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A one-number comment is enough. Please do not post confidential data, file&lt;br&gt;
paths, SQL, schemas, credentials, customer information, or screenshots.&lt;/p&gt;

&lt;p&gt;If you prefer email, use the same one-question prompt on the&lt;br&gt;
&lt;a href="https://bigdatasight.com/research" rel="noopener noreferrer"&gt;BigdataSight research page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: We build BigdataSight, a native Mac data workstation. We are&lt;br&gt;
researching evidence-backed, local-first tools for data investigation,&lt;br&gt;
reproducible verification, and workflows that are read-only by default. The&lt;br&gt;
workflow described here is research, not a shipping capability or delivery&lt;br&gt;
commitment.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Writing note: I developed and verified the technical argument in this article. AI tools assisted with English drafting and editing.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>dataengineering</category>
      <category>iceberg</category>
      <category>lakehouse</category>
    </item>
    <item>
      <title>The pipeline passed. The data still needs proof.</title>
      <dc:creator>Rui Wang</dc:creator>
      <pubDate>Wed, 29 Jul 2026 13:22:55 +0000</pubDate>
      <link>https://dev.to/bigdatasight/the-pipeline-passed-the-data-still-needs-proof-4coa</link>
      <guid>https://dev.to/bigdatasight/the-pipeline-passed-the-data-still-needs-proof-4coa</guid>
      <description>&lt;p&gt;A pipeline job finishes without an error. The new table has 18% fewer rows.&lt;br&gt;
Should you rerun the pipeline, stop the release, or trust the new output?&lt;/p&gt;

&lt;p&gt;Before rerunning the job, preserve the two states you need to compare. A rerun&lt;br&gt;
can create another state and make the original change harder to explain. The&lt;br&gt;
first useful question is: which two states are we actually comparing?&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin down the before and after
&lt;/h2&gt;

&lt;p&gt;"Yesterday" and "latest" sound precise until a file is replaced or a table&lt;br&gt;
advances to another snapshot.&lt;/p&gt;

&lt;p&gt;Give both states durable identities. That might mean a file checksum, an object&lt;br&gt;
version, a Delta table version, an Iceberg snapshot, a catalog reference, or a&lt;br&gt;
pipeline run ID. Record the local time and timezone too. They help when logs and&lt;br&gt;
object histories use different clocks.&lt;/p&gt;

&lt;p&gt;Suppose a Delta table's row-count drop occurred between versions 842 and 849.&lt;br&gt;
Those two numbers turn a vague report into a reproducible question. Without&lt;br&gt;
them, another engineer may inspect version 850 and reach a different conclusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the smallest useful explanation
&lt;/h2&gt;

&lt;p&gt;An unexpected nullable column and a lower row count point to different first&lt;br&gt;
checks.&lt;/p&gt;

&lt;p&gt;If a column became nullable, compare the two schemas before scanning rows.&lt;br&gt;
Check whether the field changed type, moved inside a nested structure, or was&lt;br&gt;
renamed. A CSV inference change and a Parquet schema change may look similar in&lt;br&gt;
a grid, but they are different events.&lt;/p&gt;

&lt;p&gt;If the row count changed, group counts by the partition or date most likely to&lt;br&gt;
explain it. A full profile of every column may cost more than the original query&lt;br&gt;
while hiding the useful difference.&lt;/p&gt;

&lt;p&gt;Delta and Iceberg add another question: which logical table state did the&lt;br&gt;
reader resolve? The newest objects in storage do not necessarily belong to the&lt;br&gt;
selected state. Check the version or snapshot, the metadata chain, and the data&lt;br&gt;
or delete files involved before blaming an individual file.&lt;/p&gt;

&lt;p&gt;The aim is a smaller search area. A larger report can wait until the evidence&lt;br&gt;
calls for one.&lt;/p&gt;

&lt;h2&gt;
  
  
  State what the check can prove
&lt;/h2&gt;

&lt;p&gt;The same finding means something different when it comes from metadata, a&lt;br&gt;
sample, or every relevant row.&lt;/p&gt;

&lt;p&gt;Metadata can establish recorded schema, partition information, and available&lt;br&gt;
statistics. It cannot prove a claim about every row. A sample helps discover a&lt;br&gt;
pattern, but a missing value in the sample does not prove that the value is&lt;br&gt;
absent. A full scan supports stronger row-level claims, provided it covered&lt;br&gt;
every relevant partition and delete.&lt;/p&gt;

&lt;p&gt;Record truncation, skipped objects, unsupported semantics, cancellation, and&lt;br&gt;
fallback behavior. If one of them prevents a conclusion, call the result&lt;br&gt;
&lt;code&gt;incomplete&lt;/code&gt;. That is more useful than a clean-looking result with a hidden gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leave evidence another engineer can challenge
&lt;/h2&gt;

&lt;p&gt;A short record is enough when another engineer can understand the decision and&lt;br&gt;
repeat the check.&lt;/p&gt;

&lt;p&gt;A fictional record might look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Recorded value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Question&lt;/td&gt;
&lt;td&gt;Why did the table lose 18% of its rows?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inputs&lt;/td&gt;
&lt;td&gt;Delta table versions 842 and 849.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checks&lt;/td&gt;
&lt;td&gt;Schema comparison and row counts grouped by day.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;Metadata plus a full scan of the affected partition.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outcome&lt;/td&gt;
&lt;td&gt;Warning. The drop is isolated to July 25, 2026.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit&lt;/td&gt;
&lt;td&gt;Delete semantics were not checked, so the cause remains unproven.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keep credentials, signed URLs, private paths, secret-bearing SQL, customer data,&lt;br&gt;
and private screenshots out of the record.&lt;/p&gt;

&lt;p&gt;Before running the checks, define the finish line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pass&lt;/strong&gt; means the stated rule held over the recorded scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warning&lt;/strong&gt; means the result needs review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure&lt;/strong&gt; means the evidence disproved the rule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incomplete&lt;/strong&gt; means the available evidence cannot support a conclusion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leave enough evidence for another engineer to reproduce the result, disagree&lt;br&gt;
with it, and run the investigation again.&lt;/p&gt;

&lt;h2&gt;
  
  
  One question for data engineers
&lt;/h2&gt;

&lt;p&gt;Which part of this work usually costs you the most time?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understanding an unexpected schema change&lt;/li&gt;
&lt;li&gt;Finding why row counts or profiles changed&lt;/li&gt;
&lt;li&gt;Understanding the real state of a Delta or Iceberg table&lt;/li&gt;
&lt;li&gt;Comparing pipeline output before and after a change&lt;/li&gt;
&lt;li&gt;Proving that a delivery or release is safe&lt;/li&gt;
&lt;li&gt;Something else&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A one-number comment is enough. Please do not post confidential data, file&lt;br&gt;
paths, SQL, schemas, credentials, customer information, or screenshots.&lt;/p&gt;

&lt;p&gt;If you prefer email, the same one-question prompt is available on the&lt;br&gt;
&lt;a href="https://bigdatasight.com/research" rel="noopener noreferrer"&gt;BigdataSight research page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build BigdataSight, a native Mac data workstation. We are&lt;br&gt;
researching evidence-backed tools for investigating changes in files and&lt;br&gt;
lakehouse tables. The product direction described here remains research and is&lt;br&gt;
not a shipping capability.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Writing note: I developed and verified the technical argument in this article. AI tools assisted with English drafting and editing.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>dataengineering</category>
      <category>database</category>
      <category>bigdata</category>
      <category>lakehouse</category>
    </item>
  </channel>
</rss>
