<?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: David Murray</title>
    <description>The latest articles on DEV Community by David Murray (@davidmurray).</description>
    <link>https://dev.to/davidmurray</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%2F4082887%2Ff10ab795-36e3-4a14-af0b-801c47c8fff3.jpg</url>
      <title>DEV Community: David Murray</title>
      <link>https://dev.to/davidmurray</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davidmurray"/>
    <language>en</language>
    <item>
      <title>Testing a Free AI SQL Assistant Against a Real Schema: A Practical Workflow</title>
      <dc:creator>David Murray</dc:creator>
      <pubDate>Tue, 13 Oct 2026 09:19:19 +0000</pubDate>
      <link>https://dev.to/davidmurray/testing-a-free-ai-sql-assistant-against-a-real-schema-a-practical-workflow-fhj</link>
      <guid>https://dev.to/davidmurray/testing-a-free-ai-sql-assistant-against-a-real-schema-a-practical-workflow-fhj</guid>
      <description>&lt;p&gt;Generating SQL with AI is the easy part. Knowing whether the generated query is correct for your schema, your dialect and your business rules is where the time actually goes.&lt;/p&gt;

&lt;p&gt;This post walks through a repeatable workflow for evaluating AI-generated SQL, with the failure modes worth checking for. It closes with a look at the free Express edition of dbForge AI Assistant introduced in &lt;a href="https://www.devart.com/dbforge/" rel="noopener noreferrer"&gt;dbForge 2026.2&lt;/a&gt;, as one example of an assistant that works inside the IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: prompts are underspecified
&lt;/h2&gt;

&lt;p&gt;Take a typical request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Total revenue per product category for last quarter, excluding cancelled orders.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before any tool can answer that correctly, someone needs to resolve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which table defines revenue: order lines, invoices or payments?&lt;/li&gt;
&lt;li&gt;Are refunds subtracted? Are discounts applied per line or per order?&lt;/li&gt;
&lt;li&gt;What are the quarter boundaries, and in which time zone?&lt;/li&gt;
&lt;li&gt;Which statuses count as cancelled?&lt;/li&gt;
&lt;li&gt;Which engine and version? Date functions and row limiting differ across SQL Server, MySQL and PostgreSQL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the assistant only sees the prompt, it fills those gaps with assumptions. So step one is removing as many assumptions as you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Give the model real context
&lt;/h2&gt;

&lt;p&gt;Useful context includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table and column names, plus keys and relationships&lt;/li&gt;
&lt;li&gt;The SQL dialect and version&lt;/li&gt;
&lt;li&gt;Business rules, for example "revenue = paid invoice lines minus refunds"&lt;/li&gt;
&lt;li&gt;The expected output shape: columns, grain, ordering&lt;/li&gt;
&lt;li&gt;Team conventions such as naming, formatting or CTE versus subquery preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drafts produced from this kind of input are much easier to review. Tools that read schema metadata directly save you from retyping the structure every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Check the grain before the numbers
&lt;/h2&gt;

&lt;p&gt;The most common silent bug in generated SQL is row multiplication from a one-to-many join. Here is an illustrative example (written for this post, not output from any tool):&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="c1"&gt;-- Looks reasonable, but can inflate totals&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_spent&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;   &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'paid'&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an order can have more than one paid payment row, each &lt;code&gt;order_total&lt;/code&gt; is counted once per payment. The query runs fine and returns wrong numbers. A safer version checks the condition without changing the grain:&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;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_spent&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;
      &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'paid'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether this matches your definition of "paid" is a business decision, which is exactly why the reviewer, not the model, makes the call. Quick checks worth running on any generated aggregate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare &lt;code&gt;COUNT(*)&lt;/code&gt; with &lt;code&gt;COUNT(DISTINCT key)&lt;/code&gt; at each join stage&lt;/li&gt;
&lt;li&gt;Spot-check a handful of rows against a source you trust&lt;/li&gt;
&lt;li&gt;Look for filters on nullable columns that may drop valid rows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Ask for explanations and minimal fixes
&lt;/h2&gt;

&lt;p&gt;When something looks off, a targeted follow-up works better than "fix this":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is the query, the error message, and the result I expected.
Dialect: PostgreSQL 16.
Explain what each join and filter does, then propose the
smallest change that produces the expected result, and explain it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Minimal diffs are easier to review than full rewrites, and the explanation tells you whether the model understood the problem or just reshuffled the query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Treat performance advice as a hypothesis
&lt;/h2&gt;

&lt;p&gt;Suggested rewrites and indexes are a starting point for investigation. Validate them like a colleague's suggestion:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm the revised query returns the same rows as the original.&lt;/li&gt;
&lt;li&gt;Compare execution plans.&lt;/li&gt;
&lt;li&gt;Compare elapsed time and resource usage under the same conditions.&lt;/li&gt;
&lt;li&gt;For index suggestions, check whether an existing index already covers the predicate, and weigh the write and storage cost.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: Fence off writes
&lt;/h2&gt;

&lt;p&gt;Generated &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt; and DDL statements go to a test database first. Run them inside a transaction you can roll back, and review them like any pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where an in-IDE assistant fits
&lt;/h2&gt;

&lt;p&gt;Every step above involves moving between a prompt, a database and an editor. An assistant inside the database tool removes some of that switching.&lt;/p&gt;

&lt;p&gt;dbForge 2026.2 introduced a free Express edition of &lt;a href="https://www.devart.com/dbforge/ai-assistant/" rel="noopener noreferrer"&gt;dbForge AI Assistant&lt;/a&gt;, which runs inside dbForge products rather than as a standalone app. The parts relevant to this workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema context:&lt;/strong&gt; attach a database and the AI Assistant works with its metadata, such as schema and index information. Several databases can share one chat, and two scripted databases can be compared.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File context:&lt;/strong&gt; attach application code, database projects, diagrams, sample SQL or custom instructions, and optionally auto-attach the document you are editing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editor round trip:&lt;/strong&gt; generated SQL moves into the SQL editor, where you test it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capabilities:&lt;/strong&gt; generating, explaining, fixing and optimizing SQL, plus questions about SQL and dbForge features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engines:&lt;/strong&gt; SQL Server, MySQL, MariaDB, Oracle, PostgreSQL and cloud services based on them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model choice:&lt;/strong&gt; Anthropic and OpenAI models can be selected under &lt;strong&gt;Tools &amp;gt; Options &amp;gt; AI Assistant &amp;gt; General&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Express edition has a limited token allowance and keeps chats for 14 days. Paid plans raise the allowance and remove the history limit.&lt;/p&gt;

&lt;p&gt;A sensible evaluation: run Steps 1 through 5 against a query you have already debugged, and see whether in-tool context shortens the loop for your schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;AI makes first drafts cheap. Correctness still comes from context, grain checks, minimal diffs, measured performance and careful handling of writes. Build those habits once and they carry over to whichever assistant you end up using.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Based on The AI Journal, &lt;a href="https://aijourn.com/free-ai-sql-assistant-is-now-available-in-dbforge-2026-2/" rel="noopener noreferrer"&gt;"Free AI SQL Assistant Is Now Available in dbForge 2026.2"&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>dbForge AI Assistant: A Developer's Tour of What It Actually Does</title>
      <dc:creator>David Murray</dc:creator>
      <pubDate>Mon, 21 Sep 2026 17:21:15 +0000</pubDate>
      <link>https://dev.to/davidmurray/dbforge-ai-assistant-a-developers-tour-of-what-itactually-does-5h7</link>
      <guid>https://dev.to/davidmurray/dbforge-ai-assistant-a-developers-tour-of-what-itactually-does-5h7</guid>
      <description>&lt;p&gt;Every database tool ships an AI assistant now, and most of the marketing sounds identical: plain English in, SQL out. That's the easy part. The more useful question for anyone actually deciding&lt;br&gt;
whether to turn one on is what it does once you're past the first demo query, across a real editing session, on a real schema, in whatever database engine you're actually using.&lt;a href="https://www.devart.com/dbforge/ai-assistant/" rel="noopener noreferrer"&gt;dbForge AI Assistant&lt;/a&gt;, built into dbForge Studio for SQL Server and the rest of the dbForge product line,&lt;br&gt;
is worth a proper walk-through for exactly that reason. Here's what it covers, feature by feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plain English to working SQL
&lt;/h2&gt;

&lt;p&gt;The core loop is text to SQL. Attach a database, describe what you want in a sentence, and the assistant returns valid SQL mapped to your actual schema, not a generic template. Because the&lt;br&gt;
schema is attached rather than pasted in as context, the same request against two different databases returns two different, correctly scoped queries. This is the baseline capability, and it's also the one most AI SQL tools advertise. What differentiates a database-native assistant from a general chatbot is everything below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing and troubleshooting queries
&lt;/h2&gt;

&lt;p&gt;Correct SQL and fast SQL are not the same thing, and this is where database context starts to matter.&lt;br&gt;
Paste in a query and the assistant returns an optimized version along with practical suggestions, flagging inefficient indexes and pointing at concrete ways to improve execution rather than generic&lt;br&gt;
textbook advice.&lt;br&gt;
A recent hands-on demo from IT educator Frank, who runs the YouTube channel Learning and Technology with Frank, shows this in practice with a 2026.1 update that has the assistant read a database's actual index metadata, the B-tree and unique indexes underneath the schema, before it recommends a rewrite. He attached a copy of Microsoft's AdventureWorks sample database, ran a generated query, asked the assistant to optimize it, and got back a rewrite that used indexes already present rather than suggesting new ones blind. It's a useful illustration of what context-aware optimization means in practice: recommendations grounded in indexes that actually exist, not ones that might.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing and explaining SQL
&lt;/h2&gt;

&lt;p&gt;Two related, everyday capabilities: error detection with auto-fix, and clause-by-clause explanation. The first spots issues in a query and returns a corrected version you can run immediately. The second&lt;br&gt;
breaks down what a query does and how it produces its results, in plain language.&lt;br&gt;
Both are aimed less at greenfield work and more at the SQL you inherited: the two-hundred-line stored procedure with no comments, the query a former teammate wrote two years ago that nobody fully&lt;br&gt;
trusts. Paste it in, ask what it does, get a walkthrough instead of an afternoon of manual tracing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond single queries
&lt;/h2&gt;

&lt;p&gt;The advanced feature set covers the parts of database work that sit around query writing rather than inside it: AI-powered formatting and style enforcement for consistent SQL across a team, generation of&lt;br&gt;
stored procedures and functions from a prompt, AI-assisted unit testing that generates tests for database objects with comments explaining how each one works, transaction and error-handling&lt;br&gt;
recommendations to prevent deadlocks and missed rollbacks, and reusable snippets you can insert from the context menu. None of these are headline features on their own, but together they cover a meaningfully larger share of routine database work than text-to-SQL alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI chat, for when you have a question
&lt;/h2&gt;

&lt;p&gt;Separate from any specific query, the assistant answers general SQL questions and questions about the dbForge product itself, in real time, without leaving the editor. Useful for the kind of question that would otherwise mean a tab switch to a search engine or a forum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it runs, and what it sends
&lt;/h2&gt;

&lt;p&gt;dbForge AI Assistant works across SQL Server, MySQL and MariaDB, Oracle and PostgreSQL, and runs inside compatible dbForge products, including dbForge Studio for SQL Server and the other engine-specific Studios, dbForge Edge, and a range of standalone dbForge tools. The same capability set applies regardless of which supported engine you're attached to.&lt;br&gt;
Worth knowing if you're evaluating it for a team with data governance requirements: the assistant sends database metadata for context, not the actual data in your tables, and only your conversation is stored&lt;br&gt;
on the server. Conversations are not used for model training. It's off by default in any dbForge product and has to be explicitly enabled.&lt;/p&gt;

&lt;p&gt;If you're deciding whether to turn on an AI assistant inside your database tool, that's the right frame: does it ground its answers in your actual schema and indexes, across the engines you actually use,&lt;br&gt;
and does it explain itself well enough that you're learning something, not just accepting output. dbForge AI Assistant works across the four major engines from inside the &lt;a href="https://www.devart.com/dbforge-studio.html" rel="noopener noreferrer"&gt;dbForge Studios&lt;/a&gt; and the other&lt;a href="https://www.devart.com/dbforge/" rel="noopener noreferrer"&gt;dbForge&lt;/a&gt; tools most SQL Server, MySQL, Oracle and PostgreSQL developers already have open,&lt;br&gt;
which is worth a look if that's what you're weighing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: “Index-Aware AI SQL Optimization in dbForge 2026.1”, Learning and Technology with Frank. Watch: &lt;a href="https://www.youtube.com/watch?v=BMFCbA-T764" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=BMFCbA-T764&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>database</category>
      <category>dataengineering</category>
      <category>sql</category>
    </item>
    <item>
      <title>Stop Sending Every SQL Query to Your Most Expensive Model — Build a Router Instead</title>
      <dc:creator>David Murray</dc:creator>
      <pubDate>Tue, 15 Sep 2026 09:52:08 +0000</pubDate>
      <link>https://dev.to/davidmurray/stop-sending-every-sql-query-to-your-most-expensive-model-build-a-router-instead-2ij3</link>
      <guid>https://dev.to/davidmurray/stop-sending-every-sql-query-to-your-most-expensive-model-build-a-router-instead-2ij3</guid>
      <description>&lt;p&gt;If you've built or integrated an AI SQL assistant into your stack, you've likely hit this wall: it works great in the demo, it works great in week one, and then usage scales and the model API bill scales right alongside it. The default fix — swap in a cheaper model everywhere — usually just trades your cost problem for a quality problem.&lt;/p&gt;

&lt;p&gt;The better fix is architectural: route each query to the model tier its actual complexity requires.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one model tier doesn't work
&lt;/h2&gt;

&lt;p&gt;SQL queries vary wildly in the reasoning they require. &lt;code&gt;SELECT * FROM users WHERE id = 4471&lt;/code&gt; and a cross-schema retention analysis using window functions are both "SQL," but they're not remotely equivalent workloads. Routing both through a frontier model is expensive overkill for the first one.&lt;/p&gt;

&lt;p&gt;A practical tiering scheme:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;th&gt;Model needed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 — Routine&lt;/td&gt;
&lt;td&gt;Simple, well-defined&lt;/td&gt;
&lt;td&gt;SELECTs, lookups, basic CRUD, syntax fixes&lt;/td&gt;
&lt;td&gt;Fast, low-cost model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 — Moderate&lt;/td&gt;
&lt;td&gt;Multi-step reasoning&lt;/td&gt;
&lt;td&gt;Joins, subqueries, aggregations, optimization hints&lt;/td&gt;
&lt;td&gt;Mid-tier model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 — Complex&lt;/td&gt;
&lt;td&gt;Deep schema reasoning&lt;/td&gt;
&lt;td&gt;Cross-DB queries, window functions, execution-plan tuning, schema refactoring&lt;/td&gt;
&lt;td&gt;Frontier model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Benchmarked figures put Tier 1 around $0.001/query versus roughly $0.03/query for a frontier model — a gap that scales linearly with volume. Tier 3 queries also need injected context (table relationships, foreign keys, indexes, dialect-specific syntax), which is expensive to carry through every request regardless of tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline: classify → route → execute → validate
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Classification
&lt;/h3&gt;

&lt;p&gt;This is the stage that determines whether the whole system works. Three implementation options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule-based (regex/AST)&lt;/strong&gt;: Detect structural signals — table count, join depth, presence of window functions or subqueries. Fast, deterministic, zero model overhead. Handles the obvious cases well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lightweight classifier model&lt;/strong&gt;: A small model trained specifically to estimate SQL complexity. Costs a fraction of a cent per call, which easily justifies itself by avoiding unnecessary frontier-model invocations. Can often run locally. Also useful for classifying natural-language prompts before SQL generation even happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hybrid&lt;/strong&gt;: Rules catch the clear cases for free; the classifier handles the ambiguous middle where structure alone doesn't tell you enough. This is the practical sweet spot for most teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing
&lt;/h3&gt;

&lt;p&gt;Beyond tier, routing decisions should also account for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema context requirements&lt;/strong&gt; — queries needing foreign key/index awareness typically need a higher-capability model regardless of surface complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency tolerance&lt;/strong&gt; — autocomplete and inline suggestions have tight budgets; background jobs don't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classifier confidence&lt;/strong&gt; — low confidence should bias toward routing up. A bad downgrade often triggers a retry, and retries are more expensive than getting it right the first time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Validation
&lt;/h3&gt;

&lt;p&gt;Post-execution checks confirm syntax correctness, sane result shapes, and schema consistency. Failures trigger escalation and a rerun at a higher tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real implementation detail worth knowing
&lt;/h2&gt;

&lt;p&gt;While building schema-aware capabilities into Devart's &lt;a href="https://www.devart.com/dbforge/ai-assistant/" rel="noopener noreferrer"&gt;dbForge AI Assistant&lt;/a&gt;, the team found that classification accuracy depended heavily on schema context — not just query structure. Queries with ambiguous table names or implicit relationships were reliably misclassified as simple and sent to models that couldn't actually resolve them correctly. The fix: feed the classifier schema metadata alongside the query itself, not just the syntax tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics that tell you if the routing is actually working
&lt;/h2&gt;

&lt;p&gt;Don't just track average cost — it hides problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost per query, by tier.&lt;/strong&gt; A blended average can look fine while masking a system that's routing 50% of queries to the wrong tier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalation rate.&lt;/strong&gt; The percentage of Tier 1/2 outputs that fail validation and need rerouting. Keep it under 5%; above that, retrain the classifier or give it more schema context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency impact.&lt;/strong&gt; Classification and routing overhead should add no more than 50–100ms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Watch for the escalation tax: a misrouted query means a classifier call + initial model call + failed validation + reroute + second model call. Stack enough of those and you can end up paying more than if you'd just routed to the frontier model directly. Track escalation rate alongside cost per call, not in isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the ROI ceiling sits
&lt;/h2&gt;

&lt;p&gt;Well-tuned routing reportedly delivers 40–60% inference cost reduction while keeping escalation under 5% and preserving quality on complex queries. Pushing past that generally requires self-hosting smaller models for Tier 1 traffic — workable, but it adds real operational overhead (infra, monitoring, model lifecycle) that not every team needs to take on.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR for implementation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build the classifier before you finalize the model lineup — it's the highest-leverage piece.&lt;/li&gt;
&lt;li&gt;A hybrid classifier (rules + lightweight model) gets you most of the savings without excess complexity.&lt;/li&gt;
&lt;li&gt;Feed the classifier schema metadata, not just query syntax — this matters more than it looks like it should.&lt;/li&gt;
&lt;li&gt;Design validation logic before you lock in classification thresholds.&lt;/li&gt;
&lt;li&gt;Track escalation rate as your primary quality signal.&lt;/li&gt;
&lt;li&gt;As local inference gets cheaper, the payoff from correct tiering only grows — the cost gap between tiers widens, not shrinks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This piece draws on an original analysis published on &lt;a href="https://www.unite.ai/ai-sql-query-routing-cost-optimization/" rel="noopener noreferrer"&gt;Unite.AI&lt;/a&gt; by Victor Horlenko, Head of AI Innovations at Devart.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>database</category>
      <category>sql</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
