<?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: Aniruddha Writes</title>
    <description>The latest articles on DEV Community by Aniruddha Writes (@aniruddhawrites).</description>
    <link>https://dev.to/aniruddhawrites</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%2Fuser%2Fprofile_image%2F459680%2Fe2363222-544a-4ae2-b559-5a6569630a1b.png</url>
      <title>DEV Community: Aniruddha Writes</title>
      <link>https://dev.to/aniruddhawrites</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aniruddhawrites"/>
    <language>en</language>
    <item>
      <title>Independence Is Not an Event. It Is a Capability.</title>
      <dc:creator>Aniruddha Writes</dc:creator>
      <pubDate>Sat, 15 Aug 2026 08:47:01 +0000</pubDate>
      <link>https://dev.to/aniruddhawrites/independence-is-not-an-event-it-is-a-capability-3acf</link>
      <guid>https://dev.to/aniruddhawrites/independence-is-not-an-event-it-is-a-capability-3acf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fob5b04ede4f532izwiu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fob5b04ede4f532izwiu5.png" alt="India's journey from independence to Digital India shows that freedom is more than a historic event. It is a capability built through institutions, infrastructure, digital trust, and continuous innovation." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Editor’s Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Every August, we celebrate the moment India became independent.&lt;/p&gt;

&lt;p&gt;But history suggests something deeper.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  11. Author's Note
&lt;/h2&gt;

&lt;p&gt;This article is a personal reflection on India's journey from political independence to digital capability. The views expressed are my own and are intended to explore the relationship between nation-building, technology, public infrastructure, and the responsibilities of the AI era.&lt;/p&gt;

&lt;p&gt;References to public digital platforms such as Aadhaar, UPI, DigiLocker, FASTag, and CoWIN are used as examples of capability-building at scale. The article is not a policy analysis, political commentary, or endorsement of any institution. It is an invitation to reflect on how capabilities are built, sustained, and strengthened across generations.&lt;/p&gt;




&lt;h2&gt;
  
  
  From nation-building to digital public infrastructure, India's journey reminds us that true independence is sustained through capabilities built and strengthened across generations.
&lt;/h2&gt;

&lt;p&gt;Independence is rarely secured in a day. It is built through capabilities that take decades to create and generations to sustain.&lt;/p&gt;

&lt;p&gt;There is a photograph most Indians have seen, even if they weren't alive to witness it: a flag rising over Red Fort as midnight becomes morning. It is one of the most reproduced images in the country's visual memory, and it captures, with total accuracy, a single instant. What it cannot capture is everything that instant required to mean something.&lt;/p&gt;

&lt;p&gt;1947 gave India the right to govern itself. It did not give India the roads to govern, the schools to educate the governed, the courts to adjudicate disputes among them, or the institutions to convert a subcontinent of extraordinary diversity into a functioning republic. That took decades. It is still taking decades. Independence, it turns out, is not the moment a nation is handed the keys. It is everything that happens afterward to make the keys worth having.&lt;/p&gt;

&lt;p&gt;This distinction — between the granting of independence and the building of it — is easy to state and hard to feel, because ceremonies are vivid and capability-building is slow. A flag-raising happens in a morning. An institution takes a generation. We remember the morning. We rarely notice the generation, because nothing about it looks like a single decisive event. It looks like thousands of unremarkable decisions, compounding.&lt;/p&gt;




&lt;h2&gt;
  
  
  The quiet decades
&lt;/h2&gt;

&lt;p&gt;Consider what had to happen between 1947 and any meaningful sense of an Indian citizen exercising self-determination in daily life. Universal adult suffrage had to be organized in a country where the majority of voters had never cast a ballot and much of the electorate could not read the ballot paper. A currency, a civil service, and a federal structure had to be built for a territory larger than most continents' worth of separate nations, each with its own language and history. Steel plants, dams, and agricultural research had to close the distance between a population and the food required to feed it.&lt;/p&gt;

&lt;p&gt;None of this made headlines the way independence itself did, because none of it was an event. It was a capability under construction — visible only in retrospect, and only in aggregate. A single dam commissioned in 1960 did not feel like sovereignty. A few hundred of them, alongside a green revolution, a literacy campaign, and a banking system extended into villages that had never seen a bank branch, eventually did. Sovereignty, it turns out, is rarely felt in the moment it is built. It is felt only once enough of it has accumulated to become invisible.&lt;/p&gt;

&lt;p&gt;This is worth sitting with, because the same pattern is now repeating in a domain that would have been unimaginable to the generation that built those dams: the digital one.&lt;/p&gt;




&lt;h2&gt;
  
  
  A second infrastructure
&lt;/h2&gt;

&lt;p&gt;Over the past decade, India has built something that rarely gets described with the gravity it deserves — not because it lacks importance, but because it doesn't look like infrastructure. It has no concrete, no steel, no ribbon to cut in front of cameras. It is a layer of shared digital rails, built by different agencies for different purposes — identity, payments, documents, mobility, public health — that together now function as one thing: a way for a citizen to be recognized, trusted, and served by systems that have never met them in person.&lt;/p&gt;

&lt;p&gt;Aadhaar, UPI, DigiLocker, FASTag, and CoWIN are, individually, products. Collectively, they are closer to what economists and technologists have started calling public digital infrastructure — shared, foundational systems that a private company, a government office, or an ordinary citizen can all build on top of, the way earlier generations built on top of roads and electricity. None of them earned their significance on launch day. Each was, for a time, simply an idea a ministry had funded and a small number of early users had tried. What made them consequential was not the announcement but the slow, cumulative process of becoming load-bearing — the moment a fruit vendor, a migrant worker, a retired teacher, and a college student each independently decided to trust the same system with something real.&lt;/p&gt;

&lt;p&gt;That moment is worth naming precisely, because it is the hinge on which this entire idea turns. A system becomes a capability at the exact moment people stop thinking about it as a system and start relying on it the way they rely on electricity — noticing it only when it's absent. A currency is not sovereign because a central bank prints it; it is sovereign because people accept it in exchange for their labor. A digital identity is not a capability because it exists in a database; it is a capability the day a citizen with no other paperwork can use it to open a bank account. Launch is permission. Adoption, sustained across millions of ordinary, unrecorded decisions to trust it again tomorrow, is proof.&lt;/p&gt;




&lt;h2&gt;
  
  
  The harder half of the work
&lt;/h2&gt;

&lt;p&gt;What is easy to overlook, amid all of this, is that building a capability and sustaining one are not the same skill, and the second is by far the less glamorous of the two. A dam can be commissioned once. It has to be maintained forever. A digital identity system can be launched once. It has to remain worthy of trust every single day after, through every new vulnerability, every policy change, every edge case that its designers never imagined. Trust of this kind is accumulated in decades and can be spent in an afternoon — which is precisely why it is not a feature to be shipped but a discipline to be practiced indefinitely. Every generation, in this sense, inherits infrastructure it did not build and did not fully choose, and its real inheritance is not the system itself but the obligation to keep it worth inheriting. The true measure of any capability, digital or institutional, is not how impressive it looked when it was new, but whether the generation that received it chose to strengthen it rather than simply spend it down.&lt;/p&gt;

&lt;p&gt;It is this obligation — not the technology itself — that connects the India of 1947 to the India now approaching a new technological threshold. The dam-builders and census-takers of the mid-twentieth century were not laying the groundwork for UPI specifically; they had no way to imagine it. What they were building was a habit: the expectation that each generation would extend what it inherited rather than merely use it up. Digital public infrastructure is that habit's most recent expression. Artificial intelligence will be its next test.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the next chapter asks for
&lt;/h2&gt;

&lt;p&gt;If public digital infrastructure was the last decade's capability-building project, the next one is already visible on the horizon, and it will not forgive complacency about what was already achieved.&lt;/p&gt;

&lt;p&gt;Artificial intelligence built on top of Aadhaar-scale identity and UPI-scale transaction data carries a different order of consequence than either system carried alone. Readiness for that shift is not primarily a question of model access or computing capacity — it is a question of whether the country's data governance, consent frameworks, and grievance-redressal mechanisms are as mature as the infrastructure they will sit on top of. Digital literacy has to extend beyond the ability to scan a QR code toward the ability to reason about what a system built on one's own data is doing. Cybersecurity has to keep pace with the fact that infrastructure this widely relied upon is now, by definition, high-value infrastructure for anyone who wishes it harm. And inclusion has to remain a design constraint, not an afterthought — because a capability that works brilliantly for the digitally fluent and poorly for everyone else is not, in the fullest sense, a national capability at all.&lt;/p&gt;

&lt;p&gt;None of this is a criticism of what has been built. It is simply what capability-building has always demanded: that today's achievement be treated as tomorrow's foundation rather than tomorrow's finish line. The systems that got India this far were themselves built by people who inherited an earlier, incomplete independence and refused to treat it as complete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkqdkx9ixuq4pvb0zbkxn.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkqdkx9ixuq4pvb0zbkxn.png%2520align%3D" alt="The Lineage No One Had Mapped" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;India's journey from political independence to the AI era can be viewed as a continuous process of capability-building. The foundation laid after 1947 through institutions, infrastructure, education, and governance created the conditions for a new layer of digital public infrastructure. Systems such as Aadhaar, UPI, DigiLocker, and CoWIN became meaningful not simply because they were launched, but because they evolved into trusted capabilities used at national scale. The next stage is not just about adopting AI, but about building the trust, literacy, governance, security, and responsible innovation needed to sustain that capability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Returning to the thesis
&lt;/h2&gt;

&lt;p&gt;It is tempting, every August, to let the story end at the flag. The story is more interesting, and more useful, if it doesn't. What 1947 actually started was not a condition but a project — one carried forward by dam engineers and census-takers, by the architects of a banking system that reached villages, by the teams who built an identity and payments layer relied upon by a scale of citizens no single generation could have imagined serving, and, soon enough, by whoever builds responsibly on top of what those systems have made possible.&lt;/p&gt;

&lt;p&gt;Independence is not an event.&lt;/p&gt;

&lt;p&gt;It is a capability — built once, and then rebuilt, generation after generation, by whoever is willing to treat the work as unfinished.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Government &amp;amp; Public Infrastructure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npci.org.in/" rel="noopener noreferrer"&gt;National Payments Corporation of India (NPCI)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://uidai.gov.in/" rel="noopener noreferrer"&gt;Aadhaar (UIDAI)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digilocker.gov.in/" rel="noopener noreferrer"&gt;DigiLocker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.netc.org.in/" rel="noopener noreferrer"&gt;FASTag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cowin.gov.in/home" rel="noopener noreferrer"&gt;CoWIN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://indiastack.org/" rel="noopener noreferrer"&gt;India Stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalindia.gov.in/" rel="noopener noreferrer"&gt;Digital Public Infrastructure initiatives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://data.rbi.org.in/DBIE/" rel="noopener noreferrer"&gt;RBI Digital Payments Reports&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://meity.gov.in/" rel="noopener noreferrer"&gt;Ministry of Electronics and Information Technology (MeitY)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  16. About the Author
&lt;/h2&gt;

&lt;p&gt;Aniruddha Bhattacharya is a Data Platform Architect, BI and Analytics leader, and technology writer with nearly two decades of experience delivering enterprise data and analytics solutions across global organizations.&lt;/p&gt;

&lt;p&gt;His writing explores the intersection of data, AI, digital transformation, architecture, and technology leadership. Through Aniruddha Writes, he shares practical insights, long-form essays, and reflections on how technology shapes organizations, industries, and society.&lt;/p&gt;

&lt;p&gt;When not working with data platforms and analytics ecosystems, he enjoys writing on technology, innovation, and the evolving relationship between people and digital systems.&lt;/p&gt;

&lt;h1&gt;
  
  
  IndependenceDay #DigitalIndia #UPI #Aadhaar #DigiLocker #CoWIN #PublicDigitalInfrastructure #AI #AIGovernance #TechnologyLeadership #NationBuilding #Innovation #DigitalTransformation #India #CapabilityBuilding
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>nationbuilding</category>
      <category>independenceday</category>
      <category>digitalindia</category>
    </item>
    <item>
      <title>The DISTKEY That Was Right, and Still Wrong</title>
      <dc:creator>Aniruddha Writes</dc:creator>
      <pubDate>Thu, 06 Aug 2026 19:50:01 +0000</pubDate>
      <link>https://dev.to/aniruddhawrites/the-distkey-that-was-right-and-still-wrong-330j</link>
      <guid>https://dev.to/aniruddhawrites/the-distkey-that-was-right-and-still-wrong-330j</guid>
      <description>

&lt;h2&gt;
  
  
  Editor's Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Enterprise data platforms rarely fail at the layer where the problem was created.&lt;/p&gt;

&lt;p&gt;More often, a modeling decision made months or years earlier quietly propagates through ingestion layers, work tables, conformed dimensions, materialized views, semantic models, and operational reporting systems until a seemingly unrelated incident finally exposes it.&lt;/p&gt;

&lt;p&gt;This case study examines one such investigation in Amazon Redshift, where a performance optimization that was technically correct revealed deeper challenges involving shared dimensions, physical design, lineage visibility, and downstream dependencies.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Morning Nothing Was Supposed to Be Wrong
&lt;/h2&gt;

&lt;p&gt;Eight-oh-four on a Tuesday. Three messages hit the team channel inside sixty seconds, from three people who hadn't talked to each other yet. That's the tell, more than the message itself — when three different people notice the same thing independently before anyone's had a chance to compare notes, you're not dealing with someone's misconfigured laptop.&lt;/p&gt;

&lt;p&gt;The exec sales dashboard — store performance, category rollups, day-over-day, built to be ready before the 8:15 leadership call — had been loading in six seconds for months. That morning it sat spinning somewhere north of ninety.&lt;/p&gt;

&lt;p&gt;Nothing had crashed. That's worth saying plainly, because it's the whole shape of the problem. No node down, no failed job, no red anything. I pulled the cluster health view at 8:06 and it looked like a Tuesday.&lt;/p&gt;

&lt;p&gt;An outage hands you a starting point — a stack trace, a failed health check, something that's already screaming at you. This wasn't that. This was a system that was healthy by every metric anyone had thought to alert on, and useless for the one thing that mattered that morning. Nobody had written an alert for "correct answer, too slow to matter," because nobody writes those until they've been burned by one.&lt;/p&gt;

&lt;p&gt;First move, before touching anything: figure out what kind of slow this is. Compute-starved, contending for something, or just doing more work than it needs to. From the outside these look identical. They are not the same fix.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stl_query&lt;/code&gt; confirmed what the frozen screen already told us — elapsed time up roughly fifteenfold against the thirty-day baseline. More useful was what hadn't moved. &lt;code&gt;svv_table_info&lt;/code&gt; showed &lt;code&gt;fact_sales&lt;/code&gt; at 3% unsorted, same as a month prior — no sort-key decay. &lt;code&gt;skew_rows&lt;/code&gt; sat near 1.0 across the tables in the join path — nothing lopsided. Cluster CPU was up a few points, nowhere near saturated. Concurrency Scaling hadn't fired once. &lt;code&gt;stl_alert_event_log&lt;/code&gt; had nothing for this query in the prior 24 hours.&lt;/p&gt;

&lt;p&gt;That's three plausible stories ruled out inside twenty minutes — not decayed, not skewed, not starved. It's tempting to read that as "we're close." I'd push back on that instinct. Ruling something out narrows the search. It doesn't tell you where the answer is. Confusing the two is how you end up an hour later, confidently wrong about something adjacent to the truth.&lt;/p&gt;

&lt;p&gt;One more thing before we go further, because it changes how you read everything that follows: this dashboard sits in Power BI on a scheduled Import refresh, not DirectQuery. That matters. "The dashboard was frozen" and "the query was slow" are two different claims, and conflating them is how you waste an hour chasing a gateway timeout that was never the problem. We checked — the refresh history showed the query itself, not the connector, eating the ninety-plus seconds. Worth the thirty seconds it took to confirm, because if we'd guessed wrong here the whole morning goes sideways.&lt;/p&gt;

&lt;p&gt;The other belief worth naming and rejecting outright: that throwing more nodes at it is a safe, reversible first move while you think. It isn't neutral. It costs money, it needs a window, and if it happens to shave a few seconds off — which it usually does, a little, for reasons that have nothing to do with your actual problem — it will convince the room the theory behind it was right. It wasn't tested. It was coincidence wearing a lab coat. We didn't resize. Worth saying, because the temptation was there, and in a lot of rooms it wins.&lt;/p&gt;

&lt;p&gt;By nine we had a narrowed problem, a clean baseline, and genuinely no cause yet. What happened next looked, at the time, like the textbook move — and it was, technically, correct. That's exactly what makes it worth telling in detail.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix That Was Right on Paper
&lt;/h2&gt;

&lt;p&gt;By nine-fifteen someone had the EXPLAIN plan up, and you could feel the room relax the way rooms do when something finally has a name. There it was — &lt;code&gt;XN Hash Join DS_DIST_BOTH&lt;/code&gt; between &lt;code&gt;fact_sales&lt;/code&gt; and &lt;code&gt;dim_store&lt;/code&gt;. Not buried. First page of any Redshift tuning guide, plain as day: both sides of the join getting redistributed across every slice, on every execution.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;svl_query_summary&lt;/code&gt; backed it up — the join step alone was moving roughly 40M rows across the network per execution, accounting for the overwhelming majority of the query's runtime. Not a guess. A number, sitting in a system table, that told you exactly where the ninety seconds were going.&lt;/p&gt;

&lt;p&gt;This wasn't a routine change to a random table, so it didn't go through routine channels — &lt;code&gt;dim_store&lt;/code&gt; sits on the shared conformed layer, which around here means anything touching it goes through an emergency-change path with a rollback script attached, not the normal weekly release window. That's the only reason "afternoon window, same day" is a true sentence and not a red flag. Worth saying explicitly, because doing this on a shared dimension without that path would be a different, worse story.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dim_store&lt;/code&gt; is Type 1 — current state only, no history retained. That's not incidental to this story; it's the reason &lt;code&gt;store_id&lt;/code&gt; is even a clean, unambiguous grain to distribute on. Had it been Type 2, with a surrogate key and multiple versions per store, "distribute on &lt;code&gt;store_id&lt;/code&gt;" stops being obviously correct — you're now co-locating on a business key that isn't the actual row-level grain, and the join locality argument gets murkier. Worth checking before you touch the DDL, not after.&lt;/p&gt;

&lt;p&gt;The change went in: DISTSTYLE from EVEN to KEY on &lt;code&gt;store_id&lt;/code&gt;, matching &lt;code&gt;fact_sales&lt;/code&gt;. Ran the query again. Eleven seconds. &lt;code&gt;svl_query_summary&lt;/code&gt; on the re-run showed the redistribution step gone entirely — replaced by a local join, no network shuffle. The ticket closed with a note that read, roughly, "root cause identified and resolved."&lt;/p&gt;

&lt;p&gt;Here's where I want to slow down, because skating past this is how the lesson gets cheapened. The fix was not wrong. I need to be precise about that — it would be a much less useful story if it were. The join genuinely was redistributing both sides, every time. The change genuinely eliminated that. Anyone in that room could defend the decision an hour later with a system-table printout in hand.&lt;/p&gt;

&lt;p&gt;The problem was the size of the question everyone agreed to answer. The question that got asked: is this DISTKEY right for this join? The question that actually mattered: is this DISTKEY right for every join that touches this table? Those sound like the same question stated more broadly. They're not.&lt;/p&gt;

&lt;p&gt;The first one you can verify in an afternoon with &lt;code&gt;svl_query_summary&lt;/code&gt;. The second one requires knowing something that lived nowhere in the platform — who else depends on &lt;code&gt;dim_store&lt;/code&gt; — because nobody had ever built a bus matrix, and the catalog tooling we had covered pipeline lineage within a team's own domain, not cross-team consumption of shared dimensions.&lt;/p&gt;

&lt;p&gt;That's not a process the team forgot to follow. It's a capability the platform never had.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diagram D2 — The Lineage No One Had Mapped
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd2.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd2.png%2520align%3D" alt="The Lineage No One Had Mapped" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;  A shared conformed dimension can act as an enterprise hub. Without complete lineage visibility, a local optimization may unknowingly impact downstream consumers that were never evaluated. *&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;A quick word on scope, because the mechanics here are Redshift's, specifically — DISTKEY, slice placement, &lt;code&gt;DS_DIST_BOTH&lt;/code&gt;. On Snowflake this conversation doesn't happen the same way; there's no distribution key to get wrong, clustering behaves on a completely different axis. On Fabric, you're reasoning about V-Order and file compaction, not which slice a row lives on.&lt;/p&gt;

&lt;p&gt;The lesson that survives the platform — a shared table has as many "correct" configurations as it has consumers, and optimizing for the loudest one is a trade, not a fix — that part travels. The mechanism doesn't.&lt;/p&gt;

&lt;p&gt;Ticket closed. Dashboard fast. Everyone went home Tuesday believing it was over.&lt;/p&gt;

&lt;p&gt;It took less than a week to learn it hadn't ended. It had moved. Two tickets landed forty-eight hours apart, filed by two teams who had no idea they were describing the same event.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Tickets, Same Week, No Shared Cause Line
&lt;/h2&gt;

&lt;p&gt;The first came from the store-traffic team Thursday afternoon.&lt;/p&gt;

&lt;p&gt;Their model — &lt;code&gt;fact_customer_traffic&lt;/code&gt;, feeding a staffing-optimization tool — had started throwing intermittent timeout errors on its late-afternoon refresh.&lt;/p&gt;

&lt;p&gt;Intermittent is the word that should slow you down.&lt;/p&gt;

&lt;p&gt;A deterministic failure is a bug.&lt;/p&gt;

&lt;p&gt;An intermittent one, on a schedule that hadn't changed, on a query that hadn't changed, on data volume that hadn't meaningfully grown — that's contention, and contention means something else is sharing the room.&lt;/p&gt;

&lt;p&gt;The second came Saturday morning, from the inventory team.&lt;/p&gt;

&lt;p&gt;Their overnight &lt;code&gt;fact_inventory&lt;/code&gt; load had blown past its four-hour SLA window twice in the same week, for the first time in over a year of stable history.&lt;/p&gt;

&lt;p&gt;Neither ticket mentioned &lt;code&gt;dim_store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Neither team had touched anything of their own.&lt;/p&gt;

&lt;p&gt;That's precisely the trap: when the thing that broke isn't the thing you own, your first instinct is to assume the platform is having a bad week, not that someone else's Tuesday-afternoon fix reached into your pipeline uninvited.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A shared table doesn't announce who it's about to affect. It just changes, and waits for the tickets to arrive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody connected the tickets immediately.&lt;/p&gt;

&lt;p&gt;They were triaged separately.&lt;/p&gt;

&lt;p&gt;Different teams.&lt;/p&gt;

&lt;p&gt;Different symptoms.&lt;/p&gt;

&lt;p&gt;Different assumptions.&lt;/p&gt;

&lt;p&gt;What eventually connected them wasn't insight.&lt;/p&gt;

&lt;p&gt;It was discipline.&lt;/p&gt;

&lt;p&gt;Both query plans touched &lt;code&gt;dim_store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That was enough reason to keep digging.&lt;/p&gt;

&lt;p&gt;The investigation stopped being about one dashboard.&lt;/p&gt;

&lt;p&gt;It became a question about the architecture itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Following the Lineage, Not the Symptom
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Environment at a Glance
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimagesimages%2Fdall.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimagesimages%2Fdall.png%2520align%3D" alt="Environment at a Glance" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point the investigation had to stop being reactive.&lt;/p&gt;

&lt;p&gt;Chasing each symptom individually would have produced three separate fixes on top of one shared cause.&lt;/p&gt;

&lt;p&gt;Instead, we traced the lineage.&lt;/p&gt;

&lt;p&gt;The platform looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;L1 — landing and standardization&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WRK — transformation and business rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DWH — conformed enterprise model&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Materialized Views — performance acceleration layer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Marts and Semantic Models — consumer-facing analytics&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Diagram D3 — One Change, Three Symptoms
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd3.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd3.png%2520align%3D" alt="One Change, Three Symptoms" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;  One physical design change produced four different outcomes. The original dashboard improved dramatically, while other consumers experienced entirely different performance symptoms through unrelated mechanisms. *&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;We traced each affected consumer through the stack.&lt;/p&gt;

&lt;p&gt;The traffic model showed memory spill.&lt;/p&gt;

&lt;p&gt;The inventory process showed I/O contention.&lt;/p&gt;

&lt;p&gt;The dashboard's materialized view showed silent fallback from incremental refresh to full recompute.&lt;/p&gt;

&lt;p&gt;Three symptoms.&lt;/p&gt;

&lt;p&gt;Three mechanisms.&lt;/p&gt;

&lt;p&gt;One upstream event.&lt;/p&gt;

&lt;p&gt;And for the first time, the investigation started moving away from the dashboard and toward the model itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "Skewed" Actually Meant Here
&lt;/h2&gt;

&lt;p&gt;The traffic-model spill deserved its own look, because it's where the investigation nearly went sideways a second time.&lt;/p&gt;

&lt;p&gt;The instinct in the room, once &lt;code&gt;svv_table_info&lt;/code&gt; showed &lt;code&gt;skew_rows&lt;/code&gt; climbing on &lt;code&gt;fact_sales&lt;/code&gt; and &lt;code&gt;fact_customer_traffic&lt;/code&gt; post-change, was to run &lt;code&gt;VACUUM&lt;/code&gt; and see if it helped.&lt;/p&gt;

&lt;p&gt;It's worth stating precisely why that instinct is wrong, because it's one of the most common misdiagnoses in Redshift work, and it nearly cost us a maintenance window we didn't need to spend.&lt;/p&gt;

&lt;p&gt;VACUUM reclaims deleted-row space and re-sorts rows within a slice's existing boundaries.&lt;/p&gt;

&lt;p&gt;It does not move rows between slices.&lt;/p&gt;

&lt;p&gt;Distribution skew — an uneven number of rows landing on different slices — is a placement problem, not a sort problem, and no amount of re-sorting within a slice changes how many rows that slice was assigned in the first place.&lt;/p&gt;

&lt;p&gt;We ran the numbers before running the command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;skew_rows&lt;/code&gt; for &lt;code&gt;fact_sales&lt;/code&gt; sat at roughly 2.3, meaning the busiest slice was holding well over double the rows of the least busy one.&lt;/p&gt;

&lt;p&gt;VACUUM was never going to touch that number.&lt;/p&gt;

&lt;p&gt;The actual cause was structural, and it was sitting in &lt;code&gt;dim_store&lt;/code&gt; all along.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;store_id&lt;/code&gt; was not an evenly distributed key.&lt;/p&gt;

&lt;p&gt;A handful of values — flagship stores and aggregated online channels — accounted for a disproportionate share of transaction volume across the platform.&lt;/p&gt;

&lt;p&gt;Co-locating fact tables on &lt;code&gt;store_id&lt;/code&gt; didn't just eliminate redistribution.&lt;/p&gt;

&lt;p&gt;It concentrated the heaviest-volume rows onto the same physical slices.&lt;/p&gt;

&lt;p&gt;For every fact table.&lt;/p&gt;

&lt;p&gt;At the same time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The fix hadn't introduced a new problem so much as it had made an old, dormant one load-bearing for the first time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction mattered.&lt;/p&gt;

&lt;p&gt;The skew wasn't created by the DISTKEY change.&lt;/p&gt;

&lt;p&gt;The skew already existed in the business.&lt;/p&gt;

&lt;p&gt;The DISTKEY change simply exposed it.&lt;/p&gt;

&lt;p&gt;Under EVEN distribution, Redshift ignored business meaning and spread rows mechanically.&lt;/p&gt;

&lt;p&gt;Under KEY distribution, Redshift inherited the real-world imbalance embedded in the business key.&lt;/p&gt;

&lt;p&gt;The platform's physical layout became a reflection of the business itself.&lt;/p&gt;

&lt;p&gt;That's where the investigation changed direction.&lt;/p&gt;

&lt;p&gt;It stopped being about distribution keys.&lt;/p&gt;

&lt;p&gt;It started being about modeling decisions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Grain Problem Underneath the Distribution Problem
&lt;/h2&gt;

&lt;p&gt;The question that actually needed answering wasn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What distribution style fixes this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The question was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does a single value in &lt;code&gt;store_id&lt;/code&gt; carry forty times the transaction volume of a normal store?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer wasn't hiding in a query plan.&lt;/p&gt;

&lt;p&gt;It was hiding in the data model.&lt;/p&gt;

&lt;p&gt;When we traced the lineage all the way back to the L1 and WRK layers, we found something that had existed for years.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dim_store&lt;/code&gt; wasn't modeling a single business concept.&lt;/p&gt;

&lt;p&gt;It was modeling two.&lt;/p&gt;

&lt;p&gt;Physical retail locations.&lt;/p&gt;

&lt;p&gt;And aggregated digital sales channels.&lt;/p&gt;

&lt;p&gt;Online sales.&lt;/p&gt;

&lt;p&gt;Marketplace integrations.&lt;/p&gt;

&lt;p&gt;Digital storefronts.&lt;/p&gt;

&lt;p&gt;All represented as single synthetic "store" rows.&lt;/p&gt;

&lt;p&gt;From a reporting perspective, the design was elegant.&lt;/p&gt;

&lt;p&gt;Every downstream report could treat online and offline channels uniformly.&lt;/p&gt;

&lt;p&gt;No branching logic.&lt;/p&gt;

&lt;p&gt;No special-case joins.&lt;/p&gt;

&lt;p&gt;No additional dimensions.&lt;/p&gt;

&lt;p&gt;But that convenience came with a hidden cost.&lt;/p&gt;

&lt;p&gt;One synthetic row represented a volume of transactions that dwarfed every physical location.&lt;/p&gt;

&lt;p&gt;As digital sales grew, that imbalance grew with them.&lt;/p&gt;

&lt;p&gt;The model encoded business skew directly into the dimension grain.&lt;/p&gt;

&lt;p&gt;No DISTKEY could fix that.&lt;/p&gt;

&lt;p&gt;No SORTKEY could fix that.&lt;/p&gt;

&lt;p&gt;No VACUUM could fix that.&lt;/p&gt;

&lt;p&gt;You can redistribute rows.&lt;/p&gt;

&lt;p&gt;You cannot redistribute the business meaning behind a row.&lt;/p&gt;

&lt;p&gt;If one value legitimately represents thirty-five percent of enterprise transactions, every physical design strategy must eventually deal with that reality.&lt;/p&gt;

&lt;p&gt;EVEN distribution hides it.&lt;/p&gt;

&lt;p&gt;KEY distribution exposes it.&lt;/p&gt;

&lt;p&gt;Neither removes it.&lt;/p&gt;

&lt;p&gt;That's the thesis of the incident.&lt;/p&gt;

&lt;p&gt;The bottleneck wasn't born in the dashboard.&lt;/p&gt;

&lt;p&gt;It wasn't born in the materialized view.&lt;/p&gt;

&lt;p&gt;It wasn't born in the DWH layer.&lt;/p&gt;

&lt;p&gt;It originated years earlier when a modeling decision defined what a "store" meant.&lt;/p&gt;

&lt;p&gt;Everything downstream was merely experiencing the consequences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Couldn't Just Fix dim_store
&lt;/h2&gt;

&lt;p&gt;The obvious solution seemed straightforward.&lt;/p&gt;

&lt;p&gt;Split the grain.&lt;/p&gt;

&lt;p&gt;Separate physical stores from digital channels.&lt;/p&gt;

&lt;p&gt;Give each concept its own dimension.&lt;/p&gt;

&lt;p&gt;Remove the concentration at the source.&lt;/p&gt;

&lt;p&gt;Technically, that would have been the cleanest solution.&lt;/p&gt;

&lt;p&gt;Operationally, it was impossible.&lt;/p&gt;

&lt;p&gt;At least not immediately.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dim_store&lt;/code&gt; wasn't an internal implementation detail.&lt;/p&gt;

&lt;p&gt;It was a published enterprise contract.&lt;/p&gt;

&lt;p&gt;Power BI semantic models depended on it.&lt;/p&gt;

&lt;p&gt;Scheduled ETL jobs depended on it.&lt;/p&gt;

&lt;p&gt;Inventory systems depended on it.&lt;/p&gt;

&lt;p&gt;Forecasting applications depended on it.&lt;/p&gt;

&lt;p&gt;External vendor integrations depended on it.&lt;/p&gt;

&lt;p&gt;Changing the grain would have meant coordinating dozens of downstream consumers.&lt;/p&gt;

&lt;p&gt;Some owned by other teams.&lt;/p&gt;

&lt;p&gt;Some owned by vendors.&lt;/p&gt;

&lt;p&gt;Some with release schedules measured in months rather than days.&lt;/p&gt;

&lt;p&gt;The issue wasn't technical complexity.&lt;/p&gt;

&lt;p&gt;The issue was dependency complexity.&lt;/p&gt;

&lt;p&gt;This is one of the most important lessons in enterprise architecture.&lt;/p&gt;

&lt;p&gt;The technically correct solution and the shippable solution are often different solutions.&lt;/p&gt;

&lt;p&gt;Interfaces become expensive precisely because they succeed.&lt;/p&gt;

&lt;p&gt;The more consumers depend on them, the harder they become to change.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dim_store&lt;/code&gt; had become successful enough to be dangerous.&lt;/p&gt;

&lt;p&gt;Changing it wasn't a database change.&lt;/p&gt;

&lt;p&gt;It was an organizational change.&lt;/p&gt;

&lt;p&gt;And organizational changes move slower than production incidents.&lt;/p&gt;

&lt;p&gt;So the redesign had to happen somewhere else.&lt;/p&gt;

&lt;p&gt;Somewhere invisible to consumers.&lt;/p&gt;

&lt;p&gt;Somewhere inside the platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Redesigning the Work Layer, Not the Interface
&lt;/h2&gt;

&lt;p&gt;The eventual solution came from separating two concepts that had accidentally become linked.&lt;/p&gt;

&lt;p&gt;Business grain.&lt;/p&gt;

&lt;p&gt;And physical distribution.&lt;/p&gt;

&lt;p&gt;Consumers cared about the business grain.&lt;/p&gt;

&lt;p&gt;Redshift cared about physical distribution.&lt;/p&gt;

&lt;p&gt;There was no requirement that they be represented by the same key.&lt;/p&gt;

&lt;p&gt;The redesign happened entirely within the WRK layer.&lt;/p&gt;

&lt;p&gt;No downstream consumer saw it.&lt;/p&gt;

&lt;p&gt;No contract changed.&lt;/p&gt;

&lt;p&gt;No semantic model needed modification.&lt;/p&gt;

&lt;p&gt;No vendor needed notification.&lt;/p&gt;

&lt;p&gt;For the handful of high-volume digital-channel records responsible for the skew, we introduced a derived distribution bucket.&lt;/p&gt;

&lt;p&gt;Instead of distributing those records solely by &lt;code&gt;store_id&lt;/code&gt;, we computed a synthetic distribution value using a secondary attribute and a hashing function.&lt;/p&gt;

&lt;p&gt;The objective wasn't to change business meaning.&lt;/p&gt;

&lt;p&gt;The objective was to spread physical placement across slices.&lt;/p&gt;

&lt;p&gt;Ordinary stores continued using their natural key.&lt;/p&gt;

&lt;p&gt;Only the concentrated digital-channel records were salted.&lt;/p&gt;

&lt;p&gt;The salting existed purely for distribution.&lt;/p&gt;

&lt;p&gt;Not for reporting.&lt;/p&gt;

&lt;p&gt;Not for analytics.&lt;/p&gt;

&lt;p&gt;Not for business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diagram D4 — WRK Layer Redesign: Salting Without Breaking the Contract
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd4.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd4.png%2520align%3D" alt="WRK Layer Redesign: Salting Without Breaking the Contract" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Salting was introduced only within the WRK layer to improve physical distribution. The business-facing grain and consumer contracts remained unchanged after reconciliation in DWH.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second part of the solution was equally important.&lt;/p&gt;

&lt;p&gt;Before anything crossed into the DWH layer, the salted buckets were re-aggregated back to the original business grain.&lt;/p&gt;

&lt;p&gt;Consumers never saw the buckets.&lt;/p&gt;

&lt;p&gt;Consumers never saw the salting.&lt;/p&gt;

&lt;p&gt;Consumers continued seeing the same &lt;code&gt;store_id&lt;/code&gt; values they always had.&lt;/p&gt;

&lt;p&gt;The contract remained unchanged.&lt;/p&gt;

&lt;p&gt;The optimization remained internal.&lt;/p&gt;

&lt;p&gt;One more thing worth flagging.&lt;/p&gt;

&lt;p&gt;The reconciliation process required rebuilding portions of the downstream structures.&lt;/p&gt;

&lt;p&gt;Whenever a large rebuild occurs, SORTKEY effectiveness should be revalidated rather than assumed.&lt;/p&gt;

&lt;p&gt;Eliminating redistribution only to lose scan pruning would have been a poor trade.&lt;/p&gt;

&lt;p&gt;We verified that the existing date-based SORTKEY strategy continued delivering the same zone-map pruning benefits after the redesign.&lt;/p&gt;

&lt;p&gt;Distribution improved.&lt;/p&gt;

&lt;p&gt;Scan efficiency remained intact.&lt;/p&gt;

&lt;p&gt;The redesign also included several supporting changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Targeted &lt;code&gt;ANALYZE&lt;/code&gt; on frequently joined and filtered columns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explicit maintenance-window scheduling for future DISTKEY changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ongoing monitoring of &lt;code&gt;skew_rows&lt;/code&gt; and &lt;code&gt;unsorted%&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validation of materialized-view refresh behavior after physical redesign&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal wasn't simply to fix one incident.&lt;/p&gt;

&lt;p&gt;It was to create guardrails that would detect the next one sooner.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Rejected, and Why
&lt;/h2&gt;

&lt;p&gt;Several alternatives were considered.&lt;/p&gt;

&lt;p&gt;Some looked attractive.&lt;/p&gt;

&lt;p&gt;Some looked simpler.&lt;/p&gt;

&lt;p&gt;None addressed the actual problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Revert &lt;code&gt;dim_store&lt;/code&gt; Back to EVEN Distribution
&lt;/h3&gt;

&lt;p&gt;This would have restored the original physical layout.&lt;/p&gt;

&lt;p&gt;It also would have restored the original dashboard problem.&lt;/p&gt;

&lt;p&gt;The Tuesday incident would return immediately.&lt;/p&gt;

&lt;p&gt;The ninety-second query would become normal again.&lt;/p&gt;

&lt;p&gt;Nothing would be learned.&lt;/p&gt;

&lt;p&gt;Nothing would be fixed.&lt;/p&gt;

&lt;p&gt;This option simply moved the pain back to its original owner.&lt;/p&gt;

&lt;p&gt;Rejected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: DISTSTYLE ALL
&lt;/h3&gt;

&lt;p&gt;At first glance, this looked promising.&lt;/p&gt;

&lt;p&gt;Replicate &lt;code&gt;dim_store&lt;/code&gt; to every node.&lt;/p&gt;

&lt;p&gt;Eliminate redistribution entirely.&lt;/p&gt;

&lt;p&gt;Allow every consumer to perform local joins.&lt;/p&gt;

&lt;p&gt;Problem solved.&lt;/p&gt;

&lt;p&gt;Except it wasn't.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dim_store&lt;/code&gt; wasn't static.&lt;/p&gt;

&lt;p&gt;It received daily updates.&lt;/p&gt;

&lt;p&gt;Type 1 changes.&lt;/p&gt;

&lt;p&gt;New channel additions.&lt;/p&gt;

&lt;p&gt;Attribute corrections.&lt;/p&gt;

&lt;p&gt;Store metadata updates.&lt;/p&gt;

&lt;p&gt;DISTSTYLE ALL makes every write more expensive because every node must maintain a copy.&lt;/p&gt;

&lt;p&gt;What appears inexpensive at today's scale often becomes technical debt at tomorrow's scale.&lt;/p&gt;

&lt;p&gt;A growing shared dimension replicated everywhere eventually becomes a write-side bottleneck.&lt;/p&gt;

&lt;p&gt;Rejected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3: Immediately Split the Grain
&lt;/h3&gt;

&lt;p&gt;From a modeling perspective, this was the cleanest solution.&lt;/p&gt;

&lt;p&gt;Separate physical stores.&lt;/p&gt;

&lt;p&gt;Separate digital channels.&lt;/p&gt;

&lt;p&gt;Eliminate the concentration.&lt;/p&gt;

&lt;p&gt;Create a more accurate business representation.&lt;/p&gt;

&lt;p&gt;Technically correct.&lt;/p&gt;

&lt;p&gt;Operationally unrealistic.&lt;/p&gt;

&lt;p&gt;Too many downstream consumers.&lt;/p&gt;

&lt;p&gt;Too many dependencies.&lt;/p&gt;

&lt;p&gt;Too many contracts.&lt;/p&gt;

&lt;p&gt;The cost of coordination exceeded the urgency of the incident.&lt;/p&gt;

&lt;p&gt;Rejected for now.&lt;/p&gt;

&lt;p&gt;Not rejected forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 4: Tune Each Consumer Individually
&lt;/h3&gt;

&lt;p&gt;This approach would have produced three separate fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One for the dashboard&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One for the traffic model&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One for inventory processing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem with symptom-based optimization is that it assumes you've already found every symptom.&lt;/p&gt;

&lt;p&gt;We hadn't.&lt;/p&gt;

&lt;p&gt;We couldn't.&lt;/p&gt;

&lt;p&gt;The actual number of consumers remained unknown.&lt;/p&gt;

&lt;p&gt;Fixing three visible problems while leaving the root cause intact simply guarantees a fourth ticket later.&lt;/p&gt;

&lt;p&gt;Rejected.&lt;/p&gt;

&lt;p&gt;The common theme across every rejected option was simple.&lt;/p&gt;

&lt;p&gt;They optimized symptoms.&lt;/p&gt;

&lt;p&gt;Not causes.&lt;/p&gt;

&lt;p&gt;The investigation had already proven where that approach leads.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Changed, Measured Carefully
&lt;/h2&gt;

&lt;p&gt;Engineering articles often overstate outcomes.&lt;/p&gt;

&lt;p&gt;This one shouldn't.&lt;/p&gt;

&lt;p&gt;The results were meaningful.&lt;/p&gt;

&lt;p&gt;Not magical.&lt;/p&gt;

&lt;p&gt;The executive dashboard returned to single-digit response times.&lt;/p&gt;

&lt;p&gt;The original query stabilized near eleven seconds after the redesign.&lt;/p&gt;

&lt;p&gt;Materialized-view refreshes returned to incremental maintenance instead of full recomputation.&lt;/p&gt;

&lt;p&gt;The staffing model stopped experiencing intermittent timeout events.&lt;/p&gt;

&lt;p&gt;Across the observation period that followed, no new memory-spill events appeared in the relevant hash-join stages.&lt;/p&gt;

&lt;p&gt;The inventory pipeline returned to its SLA window.&lt;/p&gt;

&lt;p&gt;Overnight processing consistently completed within the operational threshold required by downstream warehouse operations.&lt;/p&gt;

&lt;p&gt;The skew metrics improved substantially.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;skew_rows&lt;/code&gt; decreased from approximately 2.3 to under 1.3.&lt;/p&gt;

&lt;p&gt;Not perfect.&lt;/p&gt;

&lt;p&gt;Better.&lt;/p&gt;

&lt;p&gt;Importantly, scan efficiency remained stable.&lt;/p&gt;

&lt;p&gt;Post-redesign analysis showed no meaningful increase in blocks scanned for the dashboard's date-filtered workloads.&lt;/p&gt;

&lt;p&gt;The skew reduction did not come at the expense of SORTKEY effectiveness or zone-map pruning.&lt;/p&gt;

&lt;p&gt;That validation mattered.&lt;/p&gt;

&lt;p&gt;Performance tuning often succeeds in one dimension while quietly regressing another.&lt;/p&gt;

&lt;p&gt;This time it didn't.&lt;/p&gt;

&lt;p&gt;The outcome most people remember is the faster dashboard.&lt;/p&gt;

&lt;p&gt;The outcome I remember is different.&lt;/p&gt;

&lt;p&gt;The platform became predictable again.&lt;/p&gt;

&lt;p&gt;Engineers stopped discovering hidden consequences several days after a change.&lt;/p&gt;

&lt;p&gt;That's harder to measure.&lt;/p&gt;

&lt;p&gt;And often more valuable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diagram D5 — Before vs After: Where the Skew Lives
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd5.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fd5.png%2520align%3D" alt="Before vs After: Where the Skew Lives" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The investigation succeeded because the team stopped treating the dashboard as the problem and followed the lineage upstream until reaching the original modeling decision that created the downstream symptoms.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What's Still Unresolved
&lt;/h2&gt;

&lt;p&gt;Two things remain unresolved.&lt;/p&gt;

&lt;p&gt;Both matter.&lt;/p&gt;

&lt;p&gt;The first is the grain problem itself.&lt;/p&gt;

&lt;p&gt;Physical stores and digital channels still share the same published dimension.&lt;/p&gt;

&lt;p&gt;The salting strategy manages the consequences.&lt;/p&gt;

&lt;p&gt;It does not eliminate the underlying modeling decision.&lt;/p&gt;

&lt;p&gt;As online volume grows, the pressure on that design will grow with it.&lt;/p&gt;

&lt;p&gt;Eventually the organization may need to revisit the grain directly.&lt;/p&gt;

&lt;p&gt;The second issue is more concerning.&lt;/p&gt;

&lt;p&gt;The lineage gap still exists.&lt;/p&gt;

&lt;p&gt;The incident revealed it.&lt;/p&gt;

&lt;p&gt;The investigation worked around it.&lt;/p&gt;

&lt;p&gt;Nothing fundamentally removed it.&lt;/p&gt;

&lt;p&gt;We now know far more about &lt;code&gt;dim_store&lt;/code&gt; consumers than we did before.&lt;/p&gt;

&lt;p&gt;Mostly because we spent time manually discovering them.&lt;/p&gt;

&lt;p&gt;The next engineer facing a similar change would still need to perform much of that discovery themselves.&lt;/p&gt;

&lt;p&gt;The highest-priority follow-up is not another DISTKEY review.&lt;/p&gt;

&lt;p&gt;It is visibility.&lt;/p&gt;

&lt;p&gt;Shared assets require shared lineage.&lt;/p&gt;

&lt;p&gt;Without it, teams optimize locally and discover globally.&lt;/p&gt;

&lt;p&gt;That's exactly what happened here.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Lesson That Outlasted the Ticket
&lt;/h2&gt;

&lt;p&gt;Looking back, every individual decision made during the incident was defensible.&lt;/p&gt;

&lt;p&gt;Changing the DISTKEY was reasonable.&lt;/p&gt;

&lt;p&gt;Analyzing query plans was reasonable.&lt;/p&gt;

&lt;p&gt;Avoiding unnecessary VACUUM operations was reasonable.&lt;/p&gt;

&lt;p&gt;Rejecting DISTSTYLE ALL was reasonable.&lt;/p&gt;

&lt;p&gt;None of those decisions were mistakes.&lt;/p&gt;

&lt;p&gt;The mistake was assuming a shared enterprise object could be optimized in isolation.&lt;/p&gt;

&lt;p&gt;It couldn't.&lt;/p&gt;

&lt;p&gt;And it never could.&lt;/p&gt;

&lt;p&gt;The dashboard failure wasn't caused by the dashboard.&lt;/p&gt;

&lt;p&gt;The inventory delay wasn't caused by the inventory process.&lt;/p&gt;

&lt;p&gt;The staffing-model spill wasn't caused by the staffing team.&lt;/p&gt;

&lt;p&gt;Each symptom appeared in a different place.&lt;/p&gt;

&lt;p&gt;Each root cause pointed to the same place.&lt;/p&gt;

&lt;p&gt;A modeling decision made years earlier.&lt;/p&gt;

&lt;p&gt;One layer further upstream than anyone initially expected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Downstream symptoms are where you notice a problem. They are rarely where the problem was made.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the lesson that survives beyond Amazon Redshift.&lt;/p&gt;

&lt;p&gt;The mechanism changes across platforms.&lt;/p&gt;

&lt;p&gt;Snowflake.&lt;/p&gt;

&lt;p&gt;Fabric.&lt;/p&gt;

&lt;p&gt;Databricks.&lt;/p&gt;

&lt;p&gt;BigQuery.&lt;/p&gt;

&lt;p&gt;The pattern remains remarkably consistent.&lt;/p&gt;

&lt;p&gt;A fix appears successful.&lt;/p&gt;

&lt;p&gt;A symptom disappears.&lt;/p&gt;

&lt;p&gt;A different symptom emerges elsewhere.&lt;/p&gt;

&lt;p&gt;The real challenge is resisting the urge to stop investigating when the first visible problem goes away.&lt;/p&gt;

&lt;p&gt;We didn't close this incident.&lt;/p&gt;

&lt;p&gt;We reduced its impact.&lt;/p&gt;

&lt;p&gt;We moved the cost to a layer where it could be managed deliberately.&lt;/p&gt;

&lt;p&gt;We documented the trade-offs openly.&lt;/p&gt;

&lt;p&gt;And we identified the work that still remains.&lt;/p&gt;

&lt;p&gt;That's not a lesser outcome than "solved."&lt;/p&gt;

&lt;p&gt;At enterprise scale, with shared models and long-lived contracts, it's usually the honest one.&lt;/p&gt;

&lt;p&gt;Somewhere in that same conformed layer, another perfectly reasonable design decision is sitting quietly.&lt;/p&gt;

&lt;p&gt;Waiting for an ordinary Tuesday morning to give it somewhere to concentrate.&lt;/p&gt;

&lt;p&gt;This time, at least, we'll know where to look before the third ticket lands.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A correct DISTKEY can still create enterprise-wide problems when applied to a shared conformed dimension.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Query-level optimization and platform-level optimization are not the same thing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Distribution skew often originates from business-modeling decisions, not database-engine behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VACUUM cannot solve slice-level distribution skew.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shared dimensions are architectural contracts, not local implementation details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Physical optimization decisions should always be evaluated against all known consumers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lineage visibility is as important as performance visibility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes the best fix happens in the WRK layer, not in the published model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enterprise performance issues frequently originate multiple layers upstream from where symptoms appear.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The most valuable outcome is often predictability, not speed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Environment at a Glance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fdall.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fruddhanib.github.io%2Faniruddhawrites%2Fcontent%2Fimages%2Fdall.png%2520align%3D" alt="Before vs After: Where the Skew Lives" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The investigation succeeded because the team stopped treating the dashboard as the problem and followed the lineage upstream until reaching the original modeling decision that created the downstream symptoms.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Amazon Redshift Distribution Styles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon Redshift Sort Keys&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon Redshift Materialized Views&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon Redshift System Tables and Views&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Data Warehouse Toolkit — Ralph Kimball&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS Prescriptive Guidance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Post-Acquisition Assumption Gap
&lt;/h3&gt;

&lt;p&gt;How inherited assumptions create hidden risks across enterprise data platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Data Becomes the Bottleneck
&lt;/h3&gt;

&lt;p&gt;Unmasking the real causes behind SLA misses in modern analytics ecosystems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slowly Changing Dimensions in the Real World
&lt;/h3&gt;

&lt;p&gt;Why SCD design decisions often create consequences years after implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Author
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Aniruddha Banerjee&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Project Manager | Data Architect | Enterprise Data Engineering | Cloud &amp;amp; Analytics Platforms&lt;/p&gt;

&lt;p&gt;Sharing real-world lessons from enterprise-scale data platforms, architecture investigations, performance engineering, and operational excellence.&lt;/p&gt;

&lt;p&gt;GitHub Pages: &lt;a href="https://ruddhanib.github.io/aniruddhawrites/" rel="noopener noreferrer"&gt;https://ruddhanib.github.io/aniruddhawrites/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/ruddhani/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/ruddhani/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Medium: &lt;a href="https://ruddhani.medium.com/" rel="noopener noreferrer"&gt;https://ruddhani.medium.com/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Author's Note
&lt;/h2&gt;

&lt;p&gt;This article is inspired by recurring patterns observed across enterprise Amazon Redshift environments. Table names, business context, operational timelines, and selected implementation details have been generalized to protect confidentiality.&lt;/p&gt;

&lt;p&gt;The technical mechanisms, architectural trade-offs, investigation approaches, and performance-engineering principles described remain representative of genuine production challenges commonly encountered in large-scale analytical platforms.&lt;/p&gt;




&lt;blockquote&gt;
&lt;h1&gt;
  
  
  amazon-redshift #data-engineering #data-architecture #data-modeling #performance-optimization
&lt;/h1&gt;
&lt;/blockquote&gt;

</description>
      <category>dataengineering</category>
      <category>dataarchitecture</category>
      <category>datamodelling</category>
      <category>datawarehousing</category>
    </item>
    <item>
      <title>The Post-Acquisition Assumption Gap</title>
      <dc:creator>Aniruddha Writes</dc:creator>
      <pubDate>Sat, 18 Jul 2026 05:15:57 +0000</pubDate>
      <link>https://dev.to/aniruddhawrites/the-post-acquisition-assumption-gap-29ff</link>
      <guid>https://dev.to/aniruddhawrites/the-post-acquisition-assumption-gap-29ff</guid>
      <description>&lt;p&gt;Two years after we closed an acquisition, we found out our own pipeline still thought the company hadn't happened.&lt;/p&gt;

&lt;p&gt;Not the ERP. Not the org chart. The CDC job watching product category changes — built two years before the deal, quietly assuming there was exactly one PIM instance in the world, because at the time there was. Nobody rearchitected that assumption when the acquisition closed, because "does our pipeline's cardinality assumption survive an acquisition" isn't a line item anyone owns. Integration architecture disbands once systems are technically connected. Data engineering inherits the pipeline, not the reason it was built the way it was. The gap between those two teams is where this incident actually lives, and I want to say clearly: nobody in this story made a mistake. A category manager clicked save on a taxonomy cleanup that had been scheduled for weeks. That's the entire inciting event. Everything expensive that happened afterward was already true before she logged in.&lt;/p&gt;

&lt;p&gt;I'm going to move through the CDC-can't-capture-intent problem quickly, because if you've built distributed systems you already know this — row-level change capture answers "what changed," not "why," and no amount of tooling sophistication fixes that; you either capture intent at the write path (an outbox, a domain event) or you don't have it. What I want to spend real time on is what capturing intent actually costs you, because that part gets skipped in almost every version of this argument I've read.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Outbox Pattern — Mechanics and Its Gap
&lt;/h2&gt;

&lt;p&gt;Here's the part nobody puts in the diagram. The outbox pattern doesn't eliminate the intent-capture problem. It relocates it — from "we don't know why this changed" to "we have a &lt;code&gt;reason_code&lt;/code&gt; column, and now someone has to govern what goes in it, forever, with the same rigor you'd apply to a shared vocabulary in a multi-team API contract." That's a harder job than it sounds like, because unlike a schema, a taxonomy of &lt;em&gt;meaning&lt;/em&gt; has no compiler to enforce it. Marketing adds &lt;code&gt;'seasonal-refresh'&lt;/code&gt; because it unblocks their sprint. Nobody tells compliance, who six months later need to isolate &lt;code&gt;'regulatory-correction'&lt;/code&gt; events for an audit and discover the taxonomy has quietly drifted into unreliability.&lt;/p&gt;

&lt;p&gt;The uncomfortable version of this claim: &lt;strong&gt;most organizations that adopt the outbox pattern to solve the CDC-intent problem end up trading a technical debt they understood for a governance debt they don't have a process for at all.&lt;/strong&gt; Technical debt shows up in a code review. Taxonomy drift shows up eighteen months later, in an audit, as a surprise. I don't think this makes the pattern wrong. I think it means "we added an outbox" is not the finish line people treat it as, and if your architecture review signs off on intent-capture without also assigning a human owner to the reason-code vocabulary, you've solved the half of the problem that was easier to solve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reason-Code Governance Debt Over Time
&lt;/h2&gt;

&lt;p&gt;I think most of the SCD debate — Type 1 versus Type 2, table-level versus attribute-level, how much history is enough — is arguing about the wrong variable. The question isn't "what SCD type does this attribute deserve." It's "who is asking, and what does &lt;em&gt;they&lt;/em&gt; need to be true about the past."&lt;/p&gt;

&lt;p&gt;Finance, reconstructing last quarter's numbers, needs the category that was true on the transaction date — Type 2, strict effective dating. Merchandising, planning next season's assortment, wants the current hierarchy applied backward so trend lines are comparable to today's structure — which is functionally Type 1, applied retroactively, and is &lt;em&gt;correct&lt;/em&gt; for their question even though it's the same "wrong" behavior that blew up finance's quarter. Compliance, defending an audit, needs to know not just what the value was, but who decided it and why — which neither Type 1 nor Type 2 gives you without an outbox event attached.&lt;/p&gt;

&lt;p&gt;Three consumers. Three different correct answers. One physical attribute. Most warehouses pick one SCD treatment per attribute and call it done, because building consumer-specific temporal views is expensive — and then act surprised when one consumer's "correct" implementation is another consumer's incident. I don't think there's a clean fix for this that doesn't cost something. Type 6 hybrids (carry both the historical and current value on every row) get you partway there for two consumers at once, but they don't solve for compliance's need for decision-provenance, which requires the event-level metadata a bare dimension table was never built to hold. I'm not sure the honest answer is more sophisticated than "you need to know which consumer you're building for before you pick a strategy, and most teams pick the strategy before anyone's asked the question."&lt;/p&gt;




&lt;h2&gt;
  
  
  Consumer-Relative SCD — The Core Reframe
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;I used to tell every team the same rule: never hard-delete a crosswalk row, always end-date it. I don't hold that as a blanket rule anymore.&lt;/p&gt;

&lt;p&gt;End-dating solves a real problem — it lets you tell "this relationship expired" apart from "this relationship never existed," which a hard delete destroys completely. That part I still believe.&lt;/p&gt;

&lt;p&gt;What I left out for years: if that relationship touches anything adjacent to personal data, even indirectly, keeping it around forever in end-dated form is still retention — and some data minimization regimes have an affirmative deletion requirement that end-dating doesn't satisfy no matter how well-intentioned it is. "Never delete" and "comply with deletion law" are not always compatible instructions, and most SCD advice, mine included, has quietly assumed more history is an unqualified good. It isn't. It's a trade-off with a legal dimension I used to treat as someone else's problem.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Hard Delete vs. End-Date — The Privacy Tension
&lt;/h2&gt;

&lt;p&gt;Instead of presenting the typo/decision rows as "here's proof of the problem," frame it as a direct provocation, which lands harder and is more shareable as a standalone image:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Look at your own &lt;code&gt;dim_product&lt;/code&gt; right now. Pick any Type 2 attribute. Can you tell, from the table alone — no tribal knowledge, no Slack archaeology — which of its historical rows represent a business decision and which represent someone fixing a typo?&lt;/p&gt;

&lt;p&gt;If the answer is no, you don't have an audit trail. You have a very expensive list of things that happened, with the one piece of information that would make it useful — &lt;em&gt;why&lt;/em&gt; — living somewhere else, if it's living anywhere at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Table follows as before, now serving as evidence for a claim already made, not the claim itself.)&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bridge-Table Wager
&lt;/h2&gt;

&lt;p&gt;Call it &lt;strong&gt;the bridge-table wager.&lt;/strong&gt; Every team building a crosswalk between two systems is making an implicit bet about how many independent dimensions of change that relationship will need over its lifetime. Bet low — one dimension, effective dating alone — and a Kimball bridge table is simpler, cheaper, and analyst-friendly. Bet high — effective dating plus provenance plus, eventually, some kind of confidence scoring you haven't thought of yet — and a Data Vault Link with its own Satellite ages better, because it doesn't force every new dimension of change into the same row-versioning event.&lt;/p&gt;

&lt;p&gt;Nobody knows which bet is right at design time. That's the actual disagreement, and I don't think it resolves with more expertise — it resolves with hindsight, which is exactly the thing architecture decisions never get to have. I've watched two architects I equally respect land on opposite sides of this exact wager for reasons that were both completely defensible given what they knew when they made the call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provenance You Can't Verify
&lt;/h2&gt;

&lt;p&gt;One thing worth keeping at full strength rather than trimming: when you retrofit a &lt;code&gt;source_system&lt;/code&gt; column onto a crosswalk table that's been running for five years across three different loaders, the rows written before that column existed don't get real provenance. They get your best guess, formatted to look like data. You can infer which loader probably wrote a row from column population patterns or ID formatting, but you can't verify it, and a compliance query built on that inference is answering a question with a guess wearing a structured column's clothing. I don't think this is a solvable problem after the fact. I think it's a reason to instrument provenance on day one even when it feels like premature process, because there is no retroactive fix that isn't fiction.&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>enterprisedataarchitecture</category>
      <category>masterdatamanagement</category>
      <category>slowlychangingdimensions</category>
    </item>
    <item>
      <title>When Data Becomes the Bottleneck: Unmasking the Real Culprit Behind SLT Misses</title>
      <dc:creator>Aniruddha Writes</dc:creator>
      <pubDate>Sat, 11 Jul 2026 09:39:10 +0000</pubDate>
      <link>https://dev.to/aniruddhawrites/when-data-becomes-the-bottleneck-unmasking-the-real-culprit-behind-slt-misses-31f0</link>
      <guid>https://dev.to/aniruddhawrites/when-data-becomes-the-bottleneck-unmasking-the-real-culprit-behind-slt-misses-31f0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;We kept blaming the data. Turns out, the data was innocent. 🔍&lt;br&gt;
For weeks, our SLTs were being missed. Query timeouts. Stale dashboards. Frustrated users. Every indicator pointed at the data layer — so that's where we dug.&lt;br&gt;
What we actually found:&lt;br&gt;
🔴 The root cause wasn't bad data — it was data CONTENTION. Hundreds of concurrent queries fighting over the same shared Fabric capacity, queuing, blocking, and cascading into failure.&lt;br&gt;
🌍 And then there was the geography problem nobody had mapped — our Fabric capacity tenant sitting across the Atlantic, adding 80–150ms of round-trip latency to EVERY query. Not slow computation. Slow continents.&lt;br&gt;
The result? Gateway timeouts that looked like data failures. Connection abortions mid-flight. SLT compliance sitting at 54%.&lt;br&gt;
Once we tackled concurrency limits, workload management, and migrated our tenant region closer to our users?&lt;br&gt;
✅ Response times dropped 68%&lt;br&gt;
✅ SLT compliance hit 91%&lt;br&gt;
✅ Gateway timeouts: near zero&lt;br&gt;
The data was fine the whole time. We were just asking too much of it, from too far away.&lt;br&gt;
I believe you will be more interested 👇 — especially relevant if you're running analytics on Microsoft Fabric or dealing with cross-region BI deployments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;A deep-dive into how high-concurrency query contention and cross-Atlantic infrastructure latency quietly erode service levels — and what to do about it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Symptom Everyone Sees, The Cause Nobody Suspects
&lt;/h2&gt;

&lt;p&gt;In most performance post-mortems I've been part of, the conversation starts the same way: "The data is slow."&lt;/p&gt;

&lt;p&gt;Dashboards are lagging. Reports are timing out. Business users are frustrated. SLTs (Service Level Targets) are being breached, and fingers are pointing squarely at the data layer.&lt;/p&gt;

&lt;p&gt;And to be fair — the data is where the pain surfaces. But here's the uncomfortable truth that took us time to fully unpack:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The data wasn't broken. The data was overwhelmed — and it had a geography problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Investigation: Peeling Back the Layers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Layer 1 — SLT Misses and the Data Blame Game
&lt;/h3&gt;

&lt;p&gt;Our Service Level Targets were consistently missed during peak business hours. Query response times that should have landed under 3 seconds were stretching to 30, 60, sometimes over 120 seconds. Dashboards were either stale or outright failing to load.&lt;/p&gt;

&lt;p&gt;The immediate assumption? Data quality issues. Bad indexes. Poorly written queries. An overloaded dataset.&lt;/p&gt;

&lt;p&gt;We tuned queries. We rebuilt indexes. We optimised data models.&lt;/p&gt;

&lt;p&gt;The problem persisted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2 — The Real Root Cause: Data Contention Under Concurrent Load
&lt;/h3&gt;

&lt;p&gt;What our monitoring eventually revealed was not a quality problem but a &lt;strong&gt;concurrency problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;During peak hours, hundreds of users were simultaneously firing queries against the same datasets. The underlying engine — running on a shared Microsoft Fabric capacity — was not failing because the data was wrong. It was failing because &lt;strong&gt;too many queries were competing for the same computational resources at the same time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;data contention&lt;/strong&gt;: a condition where high volumes of concurrent queries queue up, block each other, and create a cascading slowdown that ripples all the way to the end user experience.&lt;/p&gt;

&lt;p&gt;Key symptoms we identified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query queue depth spiking&lt;/strong&gt; dramatically during 9–11 AM and 2–4 PM windows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throttling events&lt;/strong&gt; logged at the Fabric capacity level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spill-to-disk&lt;/strong&gt; operations increasing as memory pressure mounted&lt;/li&gt;
&lt;li&gt;Individual query execution time remaining acceptable in isolation, but &lt;strong&gt;degrading 10–40x under concurrent load&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data was never the culprit. &lt;strong&gt;Contention was&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3 — The Atlantic Problem: Latency Nobody Mapped
&lt;/h3&gt;

&lt;p&gt;Here is where the investigation took an unexpected turn.&lt;/p&gt;

&lt;p&gt;Our Microsoft Fabric capacity tenant was provisioned in a region &lt;strong&gt;across the Atlantic&lt;/strong&gt; — physically and network-topologically distant from the majority of our user base. What looked like slow query responses was, in many cases, not slow computation at all. It was &lt;strong&gt;network round-trip time compounding every single interaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The effects were insidious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gateway timeouts&lt;/strong&gt; — connections from local gateways to the remote Fabric tenant were breaching timeout thresholds before query results could be returned, not because queries were slow, but because the network handshake and data transfer time pushed the total wall-clock time over the edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection abortions&lt;/strong&gt; — under load, TCP connections to the distant tenant were being dropped mid-flight. The client saw a failure. The capacity was actually working — the work was simply never delivered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compounding effect&lt;/strong&gt; — contention-induced delay + cross-Atlantic latency + gateway timeout threshold = a perfect storm that made every SLT miss look far worse than the underlying compute performance warranted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A query that took 8 seconds to execute looked like a 45-second failure from the user's perspective. The network ate the difference.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The Architecture of the Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff7dxns7913py05ku10qv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff7dxns7913py05ku10qv.png" alt=" " width="777" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every query traversed this path — &lt;strong&gt;twice&lt;/strong&gt; (request and response). Under contention, queries that lingered in the execution queue long enough would cause the gateway to give up before the answer arrived.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Did About It
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Addressed Contention at the Capacity Layer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaled up Fabric capacity&lt;/strong&gt; during peak windows using autoscale policies&lt;/li&gt;
&lt;li&gt;Implemented &lt;strong&gt;query concurrency limits&lt;/strong&gt; and workload management rules to prioritise critical service-level reports&lt;/li&gt;
&lt;li&gt;Introduced &lt;strong&gt;incremental refresh and aggregation tables&lt;/strong&gt; to reduce raw query payload sizes&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shifted non-urgent batch workloads to off-peak hours to reduce simultaneous demand&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tackled the Geography Problem&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Engaged with our Fabric tenant configuration to &lt;strong&gt;migrate capacity to a region closer to our primary user base&lt;/strong&gt; — a process that required planning but delivered the most dramatic latency improvement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased &lt;strong&gt;gateway timeout thresholds&lt;/strong&gt; as an interim measure to prevent premature connection drops while longer queries completed legitimately&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented &lt;strong&gt;connection pooling and keep-alive configurations&lt;/strong&gt; on the gateway layer to reduce connection setup overhead on every request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved Observability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instrumented query telemetry to &lt;strong&gt;distinguish network latency from compute latency&lt;/strong&gt; — critical for correctly diagnosing future incidents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built a capacity utilisation dashboard to give early warning of contention events before they breached SLTs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Established a baseline for expected cross-region RTT so anomalies could be detected faster&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;p&gt;Once the contention management and regional migration work completed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Average query response time dropped by ~68%&lt;/strong&gt; during peak windows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLT compliance improved from ~54% to over 91%&lt;/strong&gt; within 6 weeks&lt;/li&gt;
&lt;li&gt;Gateway timeouts effectively dropped to near-zero&lt;/li&gt;
&lt;li&gt;User satisfaction scores for the analytics platform improved significantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data, as it turned out, had been perfectly fine the whole time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways for Data &amp;amp; Platform Engineers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't confuse the symptom with the cause&lt;/strong&gt;. Slow data experiences are often infrastructure and concurrency problems wearing a data costume.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent query volume is a first-class concern&lt;/strong&gt;. Design your capacity with peak concurrency in mind, not just peak data volume.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geography matters more than people think&lt;/strong&gt;. Cross-region tenancy is often an afterthought in platform provisioning. It shouldn't be. Measure your RTT early and often.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gateway timeouts are a network story, not a query story&lt;/strong&gt;. If timeouts correlate with specific time windows and user geographies, suspect latency before suspecting code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability must separate layers&lt;/strong&gt;. If you can't distinguish network time from compute time in your telemetry, you will misdiagnose performance problems — repeatedly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The most dangerous performance problems are the ones that look obvious but aren't. SLT misses that appear to be data problems can spend months in the wrong queue — being "fixed" by data engineers while the real causes (concurrency limits, tenant geography, gateway configuration) sit untouched.&lt;/p&gt;

&lt;p&gt;Invest the time to instrument your full stack. The answer is rarely where the pain is loudest.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Have you encountered similar patterns in your data platforms? I'd love to hear how your teams approached contention and latency challenges — drop a comment below.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;#DataEngineering #MicrosoftFabric #PowerBI #ServiceLevels #DataPlatform #CloudArchitecture #Latency #PerformanceEngineering #Analytics #DataContention #TechLeadership&lt;/code&gt;&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>msfabric</category>
      <category>dataplatform</category>
      <category>latency</category>
    </item>
  </channel>
</rss>
