<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: ConcurrentAppendException on parallel MERGE into the same Delta table, despite disjoint keys in Data Engineering</title>
    <link>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168659#M55963</link>
    <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/248581"&gt;@Islam_hoti&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This is a classic "Optimistic Concurrency Control" bottleneck in Delta Lake. Even with partitions, the MERGE operation requires a metadata-level lock on the table's transaction log, which is where your contention is happening.&lt;/P&gt;&lt;P&gt;Here is a breakdown of the answers to your questions, framed for your Architecture Review with Ilir:&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Does Row-Level Concurrency (Deletion Vectors) apply to MERGE?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;Yes, but with caveats. Deletion Vectors (DVs) improve concurrency by avoiding the need to rewrite data files during DELETE or UPDATE operations. However, when you run a MERGE, Delta still performs a "read-modify-write" operation. If two jobs are attempting to commit at the same time, the Delta protocol detects that the table version has advanced since the MERGE started, triggering the ConcurrentAppendException. DVs help with data file contention, but they do not eliminate transaction log contention.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Is Partitioning by source_system helping or hurting?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;It is currently helping by pruning data, but it is not preventing the metadata lock. Partitioning is necessary for performance, but Delta's concurrency model still checks the &lt;EM&gt;entire table's&lt;/EM&gt; transaction log for serializability. Because you are using MERGE (which is a heavy operation compared to APPEND), Delta is strictly enforcing transaction isolation. Liquid Clustering is likely a better long-term strategy for data layout, but it will not solve the concurrency conflict—in fact, it might make it worse because Liquid Clustering does not use static partitions that Delta can lock as easily.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;How to inspect the commit conflict?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;You can inspect the DESCRIBE HISTORY output to see the operation metrics. More importantly, use the delta.log files (via DESCRIBE DETAIL table_name to get the path) to see if there are frequent small commits. If you want to see exactly what happened, you can use:&lt;/P&gt;&lt;P&gt;SELECT * FROM table_changes('your_table_name', start_version, end_version)&lt;/P&gt;&lt;P&gt;This shows the actual data changes, but to see &lt;EM&gt;why&lt;/EM&gt; the conflict occurred, you need to look at the Delta Log JSON files in the _delta_log folder. If you see many small files being created, your write amplification is causing long transaction times, increasing the window for collisions.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Is one table with six concurrent writers the wrong design?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;Yes, for your current scale and frequency. The "Retry Storm" you described is a clear indicator that the architecture is hitting a physical limit of the Delta Log.&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;The Recommendation: Stop trying to force concurrent MERGE into one table.&lt;/LI&gt;&lt;LI&gt;The "Gold Standard" Alternative: Instead of a UNION view, move to a Medallion Architecture. Have each job write to its own staging table, and then have a single, separate, scheduled job that performs a MERGE from those staging tables into the final table.&lt;/LI&gt;&lt;LI&gt;Why? This decouples the "Writer" (which is now just a fast APPEND) from the "Merger" (which handles the expensive logic). This moves the complexity into a single, predictable window, eliminating the ConcurrentAppendException entirely.&lt;/LI&gt;&lt;/UL&gt;</description>
    <pubDate>Tue, 15 Sep 2026 12:08:23 GMT</pubDate>
    <dc:creator>Khasim_1</dc:creator>
    <dc:date>2026-09-15T12:08:23Z</dc:date>
    <item>
      <title>ConcurrentAppendException on parallel MERGE into the same Delta table, despite disjoint keys</title>
      <link>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168643#M55960</link>
      <description>&lt;P&gt;Hi everyone, Hoping someone has been through this, because I am running out of ideas. Setup. DBR 15.4 LTS, Unity Catalog managed Delta table, roughly 900 million rows. Six upstream sources each write into the same target table through their own job, running in parallel on a schedule. Each job does a MERGE keyed on entity_id, and the sources are disjoint, meaning no two jobs ever touch the same entity_id. The table is partitioned by source_system, and each job only ever writes its own partition value. Problem. Two or three of the six jobs fail on most runs with ConcurrentAppendException, saying files were added by a concurrent update. Retries usually succeed, but the retry storm pushes the whole window well past its SLA, and it is getting worse as the table grows. What I have tried. Adding source_system to the merge condition explicitly, so the predicate names the partition, not just the join key. This helped a little but did not eliminate it. Enabling deletion vectors, which I understood should allow row level concurrency. The exceptions still occur, though possibly less often. I am not confident this actually took effect, since I am not sure how to verify that row level concurrency is being used for a given commit. Staggering the job start times, which reduced collisions but obviously does not scale and is not a real fix. Questions. Does row level concurrency actually apply to MERGE, or only to DELETE and UPDATE? I have read conflicting things and cannot find a clear statement. Is partitioning by source_system helping or hurting here? I chose it specifically to isolate writers, but I am now wondering whether liquid clustering would give better isolation, or whether that is unrelated to the conflict detection. Is there a way to inspect a commit after the fact and see why the conflict was detected, rather than guessing at the predicate? Something in the transaction log or the history that shows which files the conflict was attributed to. And the architectural question: is a single table with six concurrent writers simply the wrong design? The alternative I am considering is six separate tables with a union view on top, but that pushes complexity onto every downstream consumer and I would rather not if the concurrency issue is solvable. Happy to share the exact merge condition and a history output if that helps narrow it down. Thanks.&lt;/P&gt;</description>
      <pubDate>Tue, 15 Sep 2026 11:03:39 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168643#M55960</guid>
      <dc:creator>Islam_hoti</dc:creator>
      <dc:date>2026-09-15T11:03:39Z</dc:date>
    </item>
    <item>
      <title>Re: ConcurrentAppendException on parallel MERGE into the same Delta table, despite disjoint keys</title>
      <link>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168653#M55961</link>
      <description>&lt;P&gt;The key point you mentioned is that table is partitioned by &lt;STRONG&gt;source_system&lt;/STRONG&gt;. Row-level concurrency does apply to MERGE, but Databricks &lt;A href="https://docs.databricks.com/aws/en/optimizations/isolation/row-level-concurrency" target="_self"&gt;documents&lt;/A&gt; that partitioned tables do not support row level concurrency, even with deletion vectors enabled. So these MERGEs can still conflict at the file/partition level.&lt;/P&gt;&lt;P&gt;If each job owns a single source_system, make that partition restriction explicit in the predicate.&lt;/P&gt;&lt;P&gt;Eg: &lt;STRONG&gt;AND t.source_system = 'SOURCE_A'&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;rather than relying only on t.source_system = s.source_system&lt;/P&gt;&lt;P&gt;Liquid clustering is relevant mainly because it lets you keep the table unpartitioned, which is compatible with row level concurrency but it does not itself guarantee conflict free writes.&lt;/P&gt;&lt;P&gt;There is also a similar community discussion around concurrent MERGE operations hitting same exception&amp;nbsp;&lt;A href="https://community.databricks.com/t5/data-engineering/concurrentappendexception-liquid-clustered-table-different-row/td-p/76916" target="_self"&gt;here&lt;/A&gt;&lt;/P&gt;&lt;P&gt;Before splitting into six tables, try validating the exact MERGE predicate and consider whether an unpartitioned table with deletion vectors / row-level concurrency is a better fit.&lt;/P&gt;</description>
      <pubDate>Tue, 15 Sep 2026 11:31:45 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168653#M55961</guid>
      <dc:creator>data_pulse</dc:creator>
      <dc:date>2026-09-15T11:31:45Z</dc:date>
    </item>
    <item>
      <title>Re: ConcurrentAppendException on parallel MERGE into the same Delta table, despite disjoint keys</title>
      <link>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168659#M55963</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/248581"&gt;@Islam_hoti&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This is a classic "Optimistic Concurrency Control" bottleneck in Delta Lake. Even with partitions, the MERGE operation requires a metadata-level lock on the table's transaction log, which is where your contention is happening.&lt;/P&gt;&lt;P&gt;Here is a breakdown of the answers to your questions, framed for your Architecture Review with Ilir:&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Does Row-Level Concurrency (Deletion Vectors) apply to MERGE?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;Yes, but with caveats. Deletion Vectors (DVs) improve concurrency by avoiding the need to rewrite data files during DELETE or UPDATE operations. However, when you run a MERGE, Delta still performs a "read-modify-write" operation. If two jobs are attempting to commit at the same time, the Delta protocol detects that the table version has advanced since the MERGE started, triggering the ConcurrentAppendException. DVs help with data file contention, but they do not eliminate transaction log contention.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Is Partitioning by source_system helping or hurting?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;It is currently helping by pruning data, but it is not preventing the metadata lock. Partitioning is necessary for performance, but Delta's concurrency model still checks the &lt;EM&gt;entire table's&lt;/EM&gt; transaction log for serializability. Because you are using MERGE (which is a heavy operation compared to APPEND), Delta is strictly enforcing transaction isolation. Liquid Clustering is likely a better long-term strategy for data layout, but it will not solve the concurrency conflict—in fact, it might make it worse because Liquid Clustering does not use static partitions that Delta can lock as easily.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;How to inspect the commit conflict?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;You can inspect the DESCRIBE HISTORY output to see the operation metrics. More importantly, use the delta.log files (via DESCRIBE DETAIL table_name to get the path) to see if there are frequent small commits. If you want to see exactly what happened, you can use:&lt;/P&gt;&lt;P&gt;SELECT * FROM table_changes('your_table_name', start_version, end_version)&lt;/P&gt;&lt;P&gt;This shows the actual data changes, but to see &lt;EM&gt;why&lt;/EM&gt; the conflict occurred, you need to look at the Delta Log JSON files in the _delta_log folder. If you see many small files being created, your write amplification is causing long transaction times, increasing the window for collisions.&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Is one table with six concurrent writers the wrong design?&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;Yes, for your current scale and frequency. The "Retry Storm" you described is a clear indicator that the architecture is hitting a physical limit of the Delta Log.&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;The Recommendation: Stop trying to force concurrent MERGE into one table.&lt;/LI&gt;&lt;LI&gt;The "Gold Standard" Alternative: Instead of a UNION view, move to a Medallion Architecture. Have each job write to its own staging table, and then have a single, separate, scheduled job that performs a MERGE from those staging tables into the final table.&lt;/LI&gt;&lt;LI&gt;Why? This decouples the "Writer" (which is now just a fast APPEND) from the "Merger" (which handles the expensive logic). This moves the complexity into a single, predictable window, eliminating the ConcurrentAppendException entirely.&lt;/LI&gt;&lt;/UL&gt;</description>
      <pubDate>Tue, 15 Sep 2026 12:08:23 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/concurrentappendexception-on-parallel-merge-into-the-same-delta/m-p/168659#M55963</guid>
      <dc:creator>Khasim_1</dc:creator>
      <dc:date>2026-09-15T12:08:23Z</dc:date>
    </item>
  </channel>
</rss>

