<?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: Manikandan</title>
    <description>The latest articles on DEV Community by Manikandan (@manikandan_2k).</description>
    <link>https://dev.to/manikandan_2k</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%2F691582%2F30e1e811-5dda-4893-b630-5416dfed8ae8.png</url>
      <title>DEV Community: Manikandan</title>
      <link>https://dev.to/manikandan_2k</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manikandan_2k"/>
    <language>en</language>
    <item>
      <title>Why LLM-to-SQL Breaks in Production</title>
      <dc:creator>Manikandan</dc:creator>
      <pubDate>Tue, 21 Jul 2026 16:50:45 +0000</pubDate>
      <link>https://dev.to/manikandan_2k/why-llm-to-sql-breaks-in-production-hen</link>
      <guid>https://dev.to/manikandan_2k/why-llm-to-sql-breaks-in-production-hen</guid>
      <description>&lt;h1&gt;
  
  
  Why LLM-to-SQL Breaks in Production: The Hidden Risks Behind Natural Language Analytics
&lt;/h1&gt;

&lt;p&gt;Natural language analytics has an irresistible promise.&lt;/p&gt;

&lt;p&gt;A CEO asks, “What was our churn last quarter?”&lt;/p&gt;

&lt;p&gt;A product manager asks, “Which feature drove the most upgrades?”&lt;/p&gt;

&lt;p&gt;A data analyst asks, “Can I break this down by customer segment?”&lt;/p&gt;

&lt;p&gt;The system writes the SQL, returns a chart, and everyone gets answers without waiting in the data queue.&lt;/p&gt;

&lt;p&gt;That is the dream. And in a demo, it often works beautifully.&lt;/p&gt;

&lt;p&gt;But production is not a demo.&lt;/p&gt;

&lt;p&gt;Production data is messy. Schemas change. Business definitions evolve. Customer permissions matter. The same phrase can mean different things to finance, product, sales, and customer success.&lt;/p&gt;

&lt;p&gt;When an LLM generates SQL in that environment, the biggest risk is not always that it fails.&lt;/p&gt;

&lt;p&gt;The bigger risk is that it succeeds quietly and gives you the wrong answer.&lt;/p&gt;

&lt;p&gt;For CEOs, CTOs, data analysts, and product managers, this matters because natural language querying is quickly becoming part of the modern analytics experience. The question is no longer whether users will want to ask questions in plain English. They will. The real question is whether the system underneath is strong enough to make those answers trustworthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Schema Changes, But The Model Keeps Living In The Past
&lt;/h2&gt;

&lt;p&gt;Most companies do not have a frozen database schema. Tables get renamed. Columns move. New lookup tables appear. Old fields stay around for backward compatibility.&lt;/p&gt;

&lt;p&gt;A small cleanup today can change the meaning of a query tomorrow.&lt;/p&gt;

&lt;p&gt;Imagine your revenue team asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is our average deal size by region this quarter?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For months, the LLM generates a query using a &lt;code&gt;region&lt;/code&gt; column on the &lt;code&gt;accounts&lt;/code&gt; table. The result is correct. Everyone trusts it.&lt;/p&gt;

&lt;p&gt;Then engineering updates the data model. Maybe &lt;code&gt;region&lt;/code&gt; becomes &lt;code&gt;sales_region&lt;/code&gt;. Maybe regions move into a new lookup table to support customers operating in multiple regions. The old &lt;code&gt;region&lt;/code&gt; column still exists, but it is no longer the source of truth.&lt;/p&gt;

&lt;p&gt;Now the LLM has a problem.&lt;/p&gt;

&lt;p&gt;It does not automatically know that the business meaning moved. If the old column still exists, the query may still run.&lt;/p&gt;

&lt;p&gt;No error. No alert. No obvious failure.&lt;/p&gt;

&lt;p&gt;It just returns a number based on stale logic.&lt;/p&gt;

&lt;p&gt;That is what makes schema drift dangerous. A broken query is easy to notice. A quietly outdated query can influence board decks, product decisions, sales forecasts, and executive dashboards before anyone realizes something changed underneath.&lt;/p&gt;

&lt;p&gt;For a data analyst, this is a trust problem.&lt;/p&gt;

&lt;p&gt;For a CTO, it is a systems problem.&lt;/p&gt;

&lt;p&gt;For a CEO, it is a decision-quality problem.&lt;/p&gt;

&lt;p&gt;The fix is not to write a better prompt and hope the model remembers more. The fix is to validate generated SQL against the live schema and the current semantic layer every time. If a field is deprecated, ambiguous, or no longer trusted, the system should fail loudly or ask for clarification instead of returning a polished-but-wrong answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Join Has More Than One “Correct” Answer
&lt;/h2&gt;

&lt;p&gt;Some questions sound simple until you ask what they actually mean.&lt;/p&gt;

&lt;p&gt;Take this one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How many active users do we have per customer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seems straightforward.&lt;/p&gt;

&lt;p&gt;But what does “active” mean?&lt;/p&gt;

&lt;p&gt;It could mean users who logged in during the last 30 days.&lt;/p&gt;

&lt;p&gt;It could mean users with &lt;code&gt;status = active&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It could mean users attached to an active subscription.&lt;/p&gt;

&lt;p&gt;It could exclude paused accounts.&lt;/p&gt;

&lt;p&gt;It could include invited users who have not logged in yet.&lt;/p&gt;

&lt;p&gt;Every one of those definitions might be reasonable in a different meeting. Product, finance, sales, and customer success may each care about a slightly different version of “active.”&lt;/p&gt;

&lt;p&gt;A good analyst knows to ask, “Which definition do you want?”&lt;/p&gt;

&lt;p&gt;An LLM often does not. It chooses a path. It picks a join. It produces a clean result. And because the output looks confident, the user may never realize the system made a business decision on their behalf.&lt;/p&gt;

&lt;p&gt;This is one of the hardest failure modes to catch because the SQL can be technically perfect. The tables exist. The joins work. The aggregation is correct. The number is internally consistent.&lt;/p&gt;

&lt;p&gt;It is just answering a different question.&lt;/p&gt;

&lt;p&gt;That is a serious product risk. If your analytics experience makes users feel fast but not accurate, trust erodes quietly. People stop relying on the product for important decisions. They go back to spreadsheets, Slack threads, and “Can you check this for me?” requests to the data team.&lt;/p&gt;

&lt;p&gt;The way forward is to stop giving the model the entire database and asking it to improvise. Instead, give it approved business definitions, trusted joins, curated metrics, and a semantic layer that reflects how the company actually talks about its data.&lt;/p&gt;

&lt;p&gt;The goal is not to make the model more creative.&lt;/p&gt;

&lt;p&gt;The goal is to make it less free to be plausibly wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Query Is Valid, But The Data Boundary Is Broken
&lt;/h2&gt;

&lt;p&gt;This is the failure mode every multi-tenant SaaS company should take seriously.&lt;/p&gt;

&lt;p&gt;Suppose a customer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show me monthly revenue by plan.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The LLM writes valid SQL. It joins the right tables. It groups by plan. It returns the right shape of result.&lt;/p&gt;

&lt;p&gt;But it forgets one thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;tenant_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a normal application flow, tenant scoping may be enforced by the backend. Every request is tied to a customer, workspace, organization, or account. The application knows what data the user is allowed to see.&lt;/p&gt;

&lt;p&gt;But an LLM-to-SQL pipeline can accidentally bypass the same assumptions if generated queries are executed in a different path.&lt;/p&gt;

&lt;p&gt;The model does not understand tenancy as a security boundary unless the system enforces it that way. To the model, &lt;code&gt;tenant_id&lt;/code&gt; may look like just another optional column. If the user did not mention a customer or tenant, the model may not include the filter.&lt;/p&gt;

&lt;p&gt;That is not just a wrong answer.&lt;/p&gt;

&lt;p&gt;That is a potential data leak.&lt;/p&gt;

&lt;p&gt;If your database already enforces row-level security, this risk is much lower because the database blocks unauthorized rows regardless of what SQL the model generates. But if tenant isolation depends only on application logic above the query execution layer, generated SQL must be treated as untrusted input.&lt;/p&gt;

&lt;p&gt;This point is critical for CTOs and product leaders: never make the LLM the place where security is enforced.&lt;/p&gt;

&lt;p&gt;The LLM can help create the query. It should not be trusted to protect the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pattern Behind All Three Failures
&lt;/h2&gt;

&lt;p&gt;These issues look different on the surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A schema changed.&lt;/li&gt;
&lt;li&gt;A business definition was ambiguous.&lt;/li&gt;
&lt;li&gt;A tenant filter was missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But underneath, they are the same problem.&lt;/p&gt;

&lt;p&gt;The model is optimizing for SQL that looks right and runs successfully. Production systems need SQL that is correct, current, scoped, and aligned with business meaning.&lt;/p&gt;

&lt;p&gt;Those are not the same thing.&lt;/p&gt;

&lt;p&gt;An LLM does not automatically know which columns are deprecated. It does not automatically know which definition of “active user” finance uses. It does not automatically know that tenant scoping is mandatory unless the infrastructure makes it mandatory.&lt;/p&gt;

&lt;p&gt;This does not mean LLM-to-SQL is a bad idea.&lt;/p&gt;

&lt;p&gt;It means LLM-to-SQL cannot be treated like magic.&lt;/p&gt;

&lt;p&gt;It is an interface, not a source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  What A Production-Ready Approach Looks Like
&lt;/h2&gt;

&lt;p&gt;The right architecture does not ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we make the prompt perfect?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What should still be true even when the model is wrong?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That mindset changes the system design.&lt;/p&gt;

&lt;p&gt;Generated SQL should be validated against the live schema, not an old snapshot.&lt;/p&gt;

&lt;p&gt;Business terms should map to approved metrics and definitions, not whatever join the model happens to choose.&lt;/p&gt;

&lt;p&gt;Tenant isolation should be enforced below the LLM, ideally at the database or execution layer.&lt;/p&gt;

&lt;p&gt;Dangerous queries should be blocked, rewritten, or routed for clarification.&lt;/p&gt;

&lt;p&gt;The system should know when to say, “I need more context,” instead of pretending every question has one obvious answer.&lt;/p&gt;

&lt;p&gt;For data analysts, this means the semantic layer becomes more important, not less. Their job shifts from writing every query by hand to defining trusted concepts that others can safely reuse.&lt;/p&gt;

&lt;p&gt;For product managers, it means the user experience should include clarification, confidence, and explainability. A fast answer is only valuable if users understand what was counted and how.&lt;/p&gt;

&lt;p&gt;For CTOs, it means NLQ belongs inside the same reliability and security model as the rest of the platform.&lt;/p&gt;

&lt;p&gt;For CEOs, it means AI analytics can speed up decision-making, but only if the foundation protects the business from confident misinformation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Promise
&lt;/h2&gt;

&lt;p&gt;Natural language analytics is not exciting because it removes SQL.&lt;/p&gt;

&lt;p&gt;It is exciting because it removes unnecessary friction between people and data.&lt;/p&gt;

&lt;p&gt;But friction is not always bad. Sometimes friction is a guardrail. Sometimes the pause before an answer is where an analyst catches an ambiguous definition, a missing filter, or a schema change that would have produced the wrong number.&lt;/p&gt;

&lt;p&gt;The best LLM-to-SQL systems will not remove all of that thinking. They will move it into the product architecture.&lt;/p&gt;

&lt;p&gt;They will make trusted definitions reusable. They will make permissions unavoidable. They will make schema changes visible. They will make ambiguity explicit.&lt;/p&gt;

&lt;p&gt;That is when natural language querying becomes more than a demo.&lt;/p&gt;

&lt;p&gt;It becomes something a business can actually trust.&lt;/p&gt;

&lt;p&gt;The demo works when nothing goes wrong.&lt;/p&gt;

&lt;p&gt;Production works when the system is built assuming something eventually will.&lt;/p&gt;

</description>
      <category>data</category>
      <category>database</category>
      <category>llm</category>
      <category>sql</category>
    </item>
    <item>
      <title>What Nobody Tells You About Enterprise Schemas and NLQ</title>
      <dc:creator>Manikandan</dc:creator>
      <pubDate>Thu, 16 Jul 2026 04:41:44 +0000</pubDate>
      <link>https://dev.to/manikandan_2k/what-nobody-tells-you-about-enterprise-schemas-and-nlq-3end</link>
      <guid>https://dev.to/manikandan_2k/what-nobody-tells-you-about-enterprise-schemas-and-nlq-3end</guid>
      <description>&lt;h1&gt;
  
  
  What Nobody Tells You About Schema Complexity When You're Building NLQ
&lt;/h1&gt;

&lt;p&gt;When we first got natural language querying working end to end, the demo was clean. Ten tables, obvious relationships, column names that matched what a business user would actually say out loud. "Show me revenue by region last quarter" turned into a correct SQL query almost every time.&lt;/p&gt;

&lt;p&gt;Then we pointed it at a real customer schema. Two hundred and forty tables. Column names like &lt;code&gt;acct_stat_cd&lt;/code&gt; and &lt;code&gt;txn_ln_amt_2&lt;/code&gt;. Three different tables that all had something called &lt;code&gt;customer_id&lt;/code&gt;, none of which meant the same thing. That's when the actual problem revealed itself — and it's not really about generating SQL. It's about figuring out which twelve tables out of two hundred and forty are even relevant to the question in the first place.&lt;/p&gt;

&lt;p&gt;I want to walk through the three layers of this problem in the order we ran into them, because each one exposes a different failure mode, and each one needed a different kind of fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer one: table and column selection
&lt;/h2&gt;

&lt;p&gt;The first wall we hit was simple in hindsight — you can't just stuff a full schema into a prompt and hope the model figures out what matters. Even with generous context windows, dumping 240 tables' worth of DDL in front of an LLM does two bad things. It buries the relevant tables in noise, and it gives the model plausible-looking but wrong tables to hallucinate joins against. A model that's seen &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_items&lt;/code&gt;, &lt;code&gt;order_archive&lt;/code&gt;, and &lt;code&gt;orders_v2&lt;/code&gt; in the same prompt will happily pick the wrong one with total confidence.&lt;/p&gt;

&lt;p&gt;The fix here is retrieval, not reasoning. Instead of asking the model to read the whole schema and decide what's relevant, we narrow the candidate set first — surfacing a small, high-confidence subset of tables and columns based on the query — and only then hand that subset to the model for SQL generation. Smaller surface area, fewer plausible wrong answers.&lt;/p&gt;

&lt;p&gt;This layer is the most "solved" of the three. Retrieval over schema metadata is a well-understood pattern at this point. It's not perfect, but it's tractable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer two: join path resolution
&lt;/h2&gt;

&lt;p&gt;Getting the right tables doesn't get you the right query. The second wall is figuring out how those tables actually connect — and this is where things get genuinely messy in enterprise schemas.&lt;/p&gt;

&lt;p&gt;Foreign keys are often missing, inconsistently enforced, or simply wrong relative to how the data is actually used. A &lt;code&gt;customer_id&lt;/code&gt; column might exist in five tables, but only three of those relationships are meaningful for a given business question, and the "correct" join path frequently isn't the shortest one — it's the one that matches how the business actually thinks about the relationship. Two tables might be joinable three different ways, each producing a technically valid but semantically different result. Ask for "customer revenue" and get three different answers depending on which join path you picked, all of them defensible, only one of them right.&lt;/p&gt;

&lt;p&gt;This is the layer where naive text-to-SQL systems quietly produce wrong-but-plausible results — the query runs, returns numbers, and nobody notices anything is off until someone cross-checks against a report they trust. That failure mode is worse than an error message, because an error at least gets investigated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer three: naming and semantic drift
&lt;/h2&gt;

&lt;p&gt;The third wall is the one that's hardest to explain to anyone who hasn't lived in enterprise data — the gap between what a business user says and what the schema calls it. "Revenue" might mean &lt;code&gt;net_amt&lt;/code&gt; in one table and &lt;code&gt;gross_txn_val&lt;/code&gt; in another, and neither name tells you which one the finance team actually means when they say "revenue" in a meeting. Column names drift from the vocabulary people actually use, sometimes because of legacy system naming conventions, sometimes because different teams built different parts of the schema at different points with different conventions.&lt;/p&gt;

&lt;p&gt;This is a mapping problem, not a language problem, and no amount of LLM sophistication resolves it on its own — the model can't infer a business definition that was never written down anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually worked: a semantic layer
&lt;/h2&gt;

&lt;p&gt;The approach that's moved the needle most for us is building an explicit semantic layer — a maintained mapping between business terminology and the underlying schema, sitting between the natural language query and the retrieval/generation steps. Instead of asking the model to infer that "revenue" means &lt;code&gt;net_amt&lt;/code&gt; in this context, that mapping is defined once, by someone who actually knows the data, and the pipeline consults it rather than guessing.&lt;/p&gt;

&lt;p&gt;Practically, this means the NLQ pipeline isn't just "user question → retrieval → SQL generation." It's closer to: user question → semantic layer lookup for business terms → schema retrieval scoped to what the mapping resolves to → SQL generation informed by both. The semantic layer doesn't replace retrieval or generation, but it constrains both — it narrows what "revenue" could plausibly mean before the model ever has to guess.&lt;/p&gt;

&lt;p&gt;The honest caveat here is that this only works as well as the semantic layer is maintained. It's not a model problem you solve once; it's an ongoing curation problem, and it doesn't fully cover the long tail. Ambiguous terms with genuinely multiple valid interpretations still need a clarification step rather than a confident guess — and we're still figuring out where that clarification should happen in the flow. Should the system ask the user? Pick the most common interpretation and flag it? Show multiple interpretations at once? We don't have a settled answer yet.&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%2F3prz6ji9bfufxrt7rviy.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%2F3prz6ji9bfufxrt7rviy.png" alt=" " width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves us
&lt;/h2&gt;

&lt;p&gt;None of these three layers are fully solved, and I'd be skeptical of anyone claiming they are for a schema of real enterprise size. Retrieval handles table selection reasonably well. Join resolution is improving but still produces confidently wrong answers often enough to matter. Naming and semantic drift is the layer that most depends on human-maintained context rather than model capability — and that's probably not going away, because business meaning isn't something you can fully derive from a schema, no matter how good the model gets at reading one.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Written by Manikandan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Software Engineer at &lt;strong&gt;&lt;a href="https://www.usedatabrain.com/" rel="noopener noreferrer"&gt;DataBrain&lt;/a&gt;&lt;/strong&gt;, where we build embedded analytics for B2B SaaS products. I write about the engineering behind enterprise analytics—tenant isolation, SQL generation, AI guardrails, security, and the product architecture required to make customer-facing analytics trustworthy.&lt;/p&gt;

&lt;p&gt;If you found this article useful, consider following me here on Medium.&lt;/p&gt;

&lt;p&gt;If your team is evaluating embedded analytics vendors or deciding whether to build analytics in-house, check out what a real proof of concept with &lt;strong&gt;&lt;a href="https://www.usedatabrain.com/" rel="noopener noreferrer"&gt;DataBrain&lt;/a&gt;&lt;/strong&gt; looks like.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
