Single-query tuning versus workload tuning decides whether one fast victory becomes a durable performance improvement.
Single-query tuning versus workload tuning looks like a choice between speed and patience. Consider an illustrative Tuesday. A twelve-second report drops below one second after a new covering index. By afternoon, order processing slows because every relevant insert must maintain that index.
One query won the race by placing a tollbooth in everybody else’s lane. The index was not wrong, and it solved the measured problem. The mistake was choosing the wrong boundary for success.
One Query Can Deserve Immediate Attention
Focused tuning is appropriate when one statement creates a clear and urgent business problem. A checkout timeout deserves attention before a monthly administrative report. A runaway query consuming most server CPU can also justify direct action. The scope is narrow because the evidence is narrow.
Start with the statement’s actual execution plan, representative parameters, and runtime measurements. Record duration, CPU, logical reads, writes, row counts, and important waits. Then identify the operator responsible for the greatest avoidable work, which connects the change to a demonstrated bottleneck.
A focused test also shortens feedback. You can change one thing, repeat comparable executions, and check whether the expected plan appears. During an incident, that evidence can support a safe, reversible change while customers remain affected.
The Database Does Not Serve One Statement
Indexes are shared database objects, not private assets of the queries requesting them. Every relevant insert, update, and delete may pay maintenance costs afterward. Other queries may use the index, ignore it, or receive different plans because it exists. Storage, memory, statistics, backups, and maintenance can also change.
This shared effect makes workload tuning a physical design problem. Chasing the fastest possible execution for every statement creates overlapping indexes and endless compromises. Aim instead for acceptable response time at the lowest sustainable cost.
Sound index design requires this balance. More indexes can help reads, but they add storage and modification overhead. The hard part is deciding which trade produces the greatest business value.
Frequency Changes the Ranking
The slowest query is not always the largest workload consumer. A ten-second statement running twice may use less CPU than a forty-millisecond lookup running one million times. Frequency turns small per-call costs into large workload costs.
Rank candidates with both per-execution cost and cumulative impact. Include execution count, total CPU, total reads, total writes, and total duration. Add business importance because numbers cannot distinguish checkout from an internal dashboard. A workload needs technical weight and operational context.
Signal
Single-query view
Workload view
Duration
Representative executions
Distribution across all executions
Reads
Logical reads per execution
Total logical reads across the period
Index value
Benefit to one plan
Net benefit across reads and writes
Success
Target improves within guardrails
Aggregate improves without unacceptable regressions
Representative Workloads Require Discipline
A workload is not every query ever captured, but a useful sample of normal and important activity. Include peak periods, parameter patterns, critical transactions, background jobs, and write-heavy operations. Remove health checks and monitoring noise when they distort the picture.
Choose samples from periods the change must serve. A peak sales hour may not resemble overnight processing. Month-end processing may deserve its own sample.
When enabled, Query Store provides persisted plan and aggregated runtime history. That history can provide a workload sample for broader physical design analysis.
Bad samples produce confident mistakes. A read-only test cannot reveal index maintenance costs from production writes. A quiet-hour capture cannot represent memory grants during peak concurrency. Capture the period that will eventually judge your change.
AI Still Needs the Correct Scope
AI can generate candidates quickly, but it cannot repair an incomplete scope. Submit one statement, and the recommendation serves that boundary. Submit related statements, and the workflow can seek a balanced index design.
The desktop AI workflow inSQL DM from IDERAcan recommend changes for one high-impact query. It also accepts a group of related queries, currently up to five selected statements. That second path seeks lower cumulative execution time across the submitted group. IDERA AI features stay disabled until an administrator enables them.
The DBA therefore remains responsible for selection and validation. Review the submitted query text, table definitions, and existing indexes, and check whether literals expose sensitive data. Recommendations arrive in a dialog for deliberate copying, so nothing bypasses normal testing and approval.
A Fair Case for Staying Narrow
Workload analysis can become an excuse for doing nothing. Teams sometimes demand perfect evidence while a known query harms customers. Nobody thanks the DBA whose complete workload study arrives after the outage.
That caution sounds responsible, but delay carries a cost. An urgent, reversible fix with strong evidence may be the right decision.
The answer is not to ignore workload effects. Set a time boundary around the focused fix. Measure the target, watch essential neighbors, document rollback, and review broader impact after stability returns. Emergency tuning and responsible tuning can be the same work.
Choose the Smallest Honest Boundary
Use single-query tuning when one statement dominates impact and the proposed change stays contained. Expand to workload tuning when queries share tables, indexes overlap, or writes carry meaningful cost. Expand again when capacity, maintenance, or business cycles change the decision.
The AI workflow inSQL DM from IDERAmakes this choice explicit. You select one problematic query or a related group in Query Monitor. A DBA can then compare duration, CPU, reads, writes, and waits in Query History. Those measurements test whether the chosen boundary matched production behavior.
Write the boundary beside the change ticket before testing begins. That small sentence stops a local metric from becoming the system’s entire definition of success.
Your next tuning decision does not need the largest scope. It needs the smallest scope that includes everyone paying for the change. Measure that group, protect it, and then enjoy the faster query.
A query fix becomes performance tuning only when its wider workload cost remains acceptable.
Anthropic’s 2026 Agentic Coding Trends Report captures an important tension in how developers use AI. Engineers report using AI in roughly 60% of their work, yet say they can fully delegate only 0–20% of their tasks. AI is becoming a constant collaborator, but it still needs setup, supervision, validation, and human judgment.
That gap is especially relevant when an agent starts working with a database.
Database requests often sound easy.
“Show me the failed orders from last week.” “Why is this query expensive?” “Does this container have the field I need?”
For a developer, answering those questions usually means opening the right account, finding the container, checking a document, writing a query, and looking at the RU charge. A coding agent can take on much of that tactical work, but only if it has more than a blank chat box. It needs a way to see the editor context, understand the actual schema, and run a query with the developer’s permission.
The interesting part isn’t that an AI can produce query text. We’ve had that for a while. The interesting part is that it can now participate in the surrounding workflow without hiding what it is doing. It fits a broader shift from writing every implementation detail toward directing agents and evaluating their work.
A query is more than query text
Asking an AI assistant to “show me all pending orders from the last seven days” sounds simple.
The hard part sits behind the sentence. Which account should Copilot use? Which database and container are open? Is the property named status, orderStatus, or something else? Is the timestamp a string or a number? And what will the query cost?
A model can’t reliably infer any of that from the prompt, and it shouldn’t pretend otherwise.
The Azure Cosmos DB Visual Studio Code extension now gives GitHub Copilot tools for working with the Cosmos DB for NoSQL Query Editor. Copilot can:
Find an open Query Editor connection
Open or focus the correct Query Editor
Inspect the current query and connection context
Sample the container schema
Apply a generated query to the editor
Execute the query and wait for its completion
So the result doesn’t have to sit in chat waiting to be copied. Copilot can put the query into the active editor and, when asked, run it there.
There is no separate @cosmosdb personality or another chat experience to learn. The regular Copilot agent uses the tools when the task calls for them.
Check the schema before guessing
One of the fastest ways to lose trust in an AI-generated query is for it to invent a property.
A developer asks for active customers, and the model confidently writes:
SELECT * FROM c WHERE c.isActive = true
It looks perfectly reasonable. It is also useless if the real property is accountStatus.
Before generating a query, Copilot can sample the active container and infer the property names and types it actually finds. The query is then based on the developer’s data instead of the model’s best guess.
The sampled schema is useful outside chat too. It also improves editor autocompletion and result-schema inference.Sampling isn’t silent. It reads data and consumes request units, so the extension asks first. Query execution follows the same rule. That small pause matters. Copilot can prepare the work, but the developer decides when it touches data or spends RUs.
Tools still need database judgment
Tool access solves only half of the problem.
An agent may know how to execute a query and still generate one that is inefficient or invalid for Cosmos DB. It might use relational JOIN semantics, write unsupported DML, scan every partition, or query when a point read would be cheaper.
This is why the extension also ships dedicated agent skills. They give Copilot the Cosmos DB-specific guidance that a generic model won’t always have. The Azure Cosmos DB for NoSQL Query Generation skill teaches Copilot the NoSQL query dialect, including projections, array-unwind joins, aggregates, full-text search, vector search, hybrid ranking, pagination, and supported built-in functions. The Query Editor skill teaches the agent how to use the editor tools: inspect context, sample the schema, apply the query, and execute it when the developer asks to see results.
The Azure Cosmos DB Agent Kit skill covers more than 100 recommendations across data modeling, partition-key design, query optimization, SDK usage, indexing, throughput, global distribution, monitoring, vector search, full-text search, and agent application patterns.
I find the distinction useful: tools give the agent hands; skills give it a working knowledge of the database.
The Agent Kit brings that knowledge into everyday coding across GitHub Copilot, Claude Code, Codex, Cursor, Gemini CLI, and other compatible agents, letting developers ask about repository implementations, partition keys, or indexing policies without repeatedly pasting documentation into each conversation.
Keep a person in the loop
The moment an agent can reach a database, the boundaries need to be obvious. Anthropic calls this the “collaboration paradox.” Developers use AI frequently and see meaningful productivity gains, but they tend to delegate work that is well-defined, low-risk, or easy to verify. More consequential work stays collaborative. Database access belongs firmly in that second category.
The extension doesn’t quietly keep entire query results in its agent-facing history. It records the query text and useful metadata, including row counts, request charges, and inferred schemas, rather than raw documents. Schema sampling asks for consent. Query execution asks for consent. The generated query lands in the Query Editor, where it can be read and changed before anything happens.
It is a practical division of responsibility: Copilot handles discovery, syntax, and the repetitive steps; the developer keeps control of data access and execution. Human attention is spent on the moments that carry cost, security, or business impact rather than on every mechanical step.
Connections can also use Microsoft Entra ID, managed identity, connection strings, Azure CLI authentication, and read-only keys depending on the tool and environment. Existing Cosmos DB permissions continue to determine what the connected identity is allowed to do.
An agent shouldn’t become a back door around database security. It should work through the same identities and permissions as the person or application it represents. As agents become more capable, security has to be part of the architecture from the beginning rather than added after the workflow is automated.
When the Query Editor isn’t the whole workflow
The Query Editor is a natural home for query work, but not every agent stays inside it.
Another forecast in the report is that agent tasks will grow from short, one-shot requests into workflows that run for hours or days and recover from failures along the way. Those longer-running workflows need durable, explicit ways to reach their tools; a pasted query and a short-lived chat context are not enough.
Azure Cosmos DB Shell provides a lightweight, command-line experience for navigating accounts, databases, containers, and items. It supports queries, management operations, scripting, and multiple authentication methods.
ark-themed Azure Cosmos DB Shell interface showing a terminal with commands for browsing databases and containers and displaying JSON documents, alongside highlights for CLI, real-time data exploration, JSON-first workflows, and performance.
The shell also has an optional MCP server mode. Once a developer enables it, GitHub Copilot and other MCP-compatible clients can use shell operations as tools.
That leaves developers with two sensible paths: native, schema-aware Query Editor tools inside VS Code, and Cosmos DB Shell through MCP for workflows that reach beyond the editor.
One detail is worth being plain about: this is not a hosted, managed MCP service. It is optional, runs under the developer’s control, and must be enabled explicitly. Teams still need to decide where it runs, which identity it uses, and what that identity is allowed to do.
Start with fake data and a local database
An agent shouldn’t need production data to prove it can write a query.
The Azure Cosmos DB Emulator gives developers a local service for exactly this kind of work. Attach it to the VS Code extension, create a few realistic containers, and exercise the Query Editor workflow before pointing an agent at a cloud account.
The Linux-based vNext Emulator runs in Docker and includes Data Explorer and Azure Cosmos DB Shell. Seed scripts make test data repeatable, while health probes make the container usable in automated tests. Teams can run it in CI as well, avoiding the familiar problem of one shared development database slowly becoming everybody’s mystery state.
For agent work, use synthetic documents that have the awkward parts of real data: missing fields, inconsistent shapes, and values no one expected. Then test whether schema sampling keeps the generated query honest. This makes active validation concrete. If the agent goes wrong, it goes wrong locally, and the failure can become a repeatable test.
The Emulator isn’t the cloud in a Docker container. The vNext version supports the API for NoSQL in gateway mode and only a subset of cloud capabilities. Request-unit behavior and some production features aren’t fully represented. Use it for functional confidence, then validate performance, indexing, security, scale, and regional behavior in Azure.
Stay in the flow
The best database tool is usually the one that doesn’t pull a developer away from the problem they were solving.
From the Cosmos DB Query Editor, a developer can select Generate query, describe what they need in ordinary language, review the generated NoSQL query, and run it. They can also ask Copilot to explain an existing query.
The results remain in the familiar Query Editor, with table, JSON, and tree views. Developers can inspect execution time, request-unit consumption, query metrics, and index recommendations without moving the investigation to another product.
A typical request might be:
“Show me the ten most recent failed payment attempts for this tenant.”
Copilot can identify the active container, ask to sample its schema, generate a partition-scoped query with the real property names, and place it in the editor. The developer can read it, change it, and approve execution.
The useful part isn’t the SQL-like text. It is getting through the small surrounding steps without losing sight of the query or what it costs.
Before the first query and after the thousandth
Not every Cosmos DB project starts from an empty repository.
The AI-assisted Migration Assistant, currently in preview, helps teams examine a relational workload before moving it to Cosmos DB. It guides developers through source-schema discovery, access-pattern analysis, workload estimates, application requirements, and conversion to a Cosmos DB target model.
That matters because moving to Cosmos DB isn’t a mechanical table-to-container conversion. The target model has to reflect how the application actually reads and writes data.
Once an application is running, the extension’s Account Overview dashboard provides a read-only view of inventory, throughput, normalized RU consumption, partition health, alerts, recommendations, and derived advisories.
These are two ends of the same job. AI can help a team reason about the move and investigate queries later, but people still need a clear view of cost, partition behavior, and account health once the system is real.
The point isn’t autonomy
None of this removes developers from database work. It removes some of the hunting, copying, and syntax recall around that work.
This broader model can help engineers work across more of the stack, with AI filling knowledge gaps while people provide direction and judgment. Cosmos DB tools and skills are a practical example: they let a developer move from application code into data exploration, query design, local testing, and account diagnostics without pretending that database expertise no longer matters.
A developer can describe the outcome, let Copilot assemble the steps, and still inspect the query, approve access, review its RU cost, and decide what happens next.
Azure Cosmos DB now provides several ways to support that collaboration:
Native GitHub Copilot tools in the VS Code extension
Schema-grounded natural-language query generation
Cosmos DB query and best-practice agent skills
Optional MCP support through Azure Cosmos DB Shell
Local agent development and CI testing with the Azure Cosmos DB Emulator
AI-assisted relational migration
Operational visibility through the Account Overview dashboard
The goal isn’t unrestricted database access for an agent. It is enough context and capability to be genuinely useful, with a person still able to see and control the consequential parts.
For me, that is the useful shape of database tooling in this new workflow: grounded in the real schema, honest about cost, governed by identity, and close to where the developer is already working.
About Azure Cosmos DB
Azure Cosmos DB is a fully managed and serverless NoSQL and vector database for modern app development, including AI applications. With its SLA-backed speed and availability as well as instant dynamic scalability, it is ideal for real-time NoSQL and MongoDB applications that require high performance and distributed computing over massive volumes of NoSQL and vector data.
To stay in the loop on Azure Cosmos DB updates, follow us on X, YouTube, and LinkedIn.
Aspire 13 thus far has been all about expanding Aspire’s capabilities across languages, deployment targets, and coding agents. We’ve shipped a full-parity TypeScript AppHost, tons of CLI features, an optimized docs workflow, Kubernetes and Docker Compose deployment integrations, and plenty more. We figured that after a crazy half of a year, it was time to take a step back, freshen up our look, and spend time on some much-requested quality-of-life features.
Today, we shipped Aspire 13.5. The dashboard has a visual refresh, aspire.dev has a redesigned homepage, and a pile of usability improvements smooth out even more of your day-to-day dev experience. This release also gives your AppHost more ways to interact with you directly, from file uploads and progress dialogs to a full terminal session hosted in the dashboard and accessible from the CLI.
Deployment with Aspire has gotten more flexible, too. You can model persistent volumes for Kubernetes, reference existing Azure resources across subscriptions and tenants, and express more deployment specifics in C# or TypeScript in the AppHost so you never have to write YAML again.
This blog highlights some of my favorites. For the complete inventory, migration notes, and breaking changes, check out the What’s new in Aspire 13.5 page on our docs.
Let’s start with the part you will notice immediately. Our website’s homepage and the dashboard got a fresh coat of paint! The overall experience, layout, and features didn’t change, so everything is still where you expect it. We just thought it was time for an updated look and feel. Of course, we checked contrast and accessibility across the updated surfaces so the new look works great for everyone.
The dashboard also got a lot of smaller improvements that you have been asking for:
Filter console logs with a case-insensitive text search.
Filter logs and traces by timestamp, or use exact numeric comparisons.
Reconnect cleanly when the dashboard loses its resource-service connection.
Friendlier health-check failures instead of raw exception stacks.
Keep telemetry streaming correctly while resource filters are active.
Your AppHost can ask for files
The Interaction Service and resource commands elevate Aspire from a fancy launch script to a customized developer experience that lives in your source. A resource command can ask for input, validate the answer, show a notification, or open a message box right where the developer is already working.
In 13.5, we added file import support to commands. Picture a resource command named Import configuration. It opens a file picker that accepts JSON or YAML, enforces a size limit, sends the file to the AppHost, and gives the command a stream to read. No “put this file in a magic directory, then run the script from the README” detour.
Longer work can also now show a progress dialog with optional cancellation, and resource commands can declare named arguments that become input controls in the dashboard and --name options in the CLI. Together, that gives integration authors the pieces for a complete setup or import flow: collect exactly what the command needs, run the work, and return a useful result.
Preview API
The core Interaction Service and file input APIs are stable. Progress dialogs still use the experimental ASPIREINTERACTION001 diagnostic in 13.5.
We put a terminal in the dashboard
Some resources are not background services with logs. They are REPLs, shells, terminal user interfaces, and interactive tools that expect a real stdin and stdout. Until now, running one inside your distributed app meant keeping a separate terminal around and mentally matching it back to the resource in Aspire.
In 13.5, add WithTerminal() and the resource gets an interactive terminal session inside the dashboard. You can type into it, switch between replicas, and move back to the normal console logs without stopping the session. Multiple viewers can attach at once, so a dashboard tab and a local terminal can watch the same process.
The Aspire repository has a tiny guessing game playground for this. The game runs as a JavaScript resource from a TypeScript AppHost, and the whole thing is playable in the dashboard. It is a wonderfully unnecessary and yet perfect way to prove that the in-dashboard terminal is real
The matching aspire terminal commands can list sessions and attach from your shell after you enable the terminal command feature flag.
Preview API
WithTerminal() and the aspire terminal commands are experimental in 13.5. Resources using a terminal run as plain processes for now, so attach the debugger manually when you need it.
The AppHost should describe the infrastructure your app actually uses. Aspire 13.5 makes that model more complete for both Kubernetes workloads and existing Azure resources.
Persistent storage for Kubernetes workloads
You can add a persistent volume to a Kubernetes or AKS environment, configure its storage class, capacity, and access mode, then bind it to a project or container workload.
var k8s = builder.AddKubernetesEnvironment("k8s");
var data = k8s.AddPersistentVolume("data")
.WithStorageClass("managed-csi")
.WithCapacity("20Gi")
.WithAccessMode(PersistentVolumeAccessMode.ReadWriteOnce);
builder.AddContainer("postgres", "postgres:16")
.WithVolume("data", "/var/lib/postgresql/data")
.WithPersistentVolume(data);
PostgreSQL needs durable storage, so you say so next to PostgreSQL. Aspire emits the persistent volume claim and renders the workload as a StatefulSet.
Preview API
The compute-environment persistent volume APIs are experimental and use the ASPIRECOMPUTE002 diagnostic in 13.5.
Your app might use a shared Service Bus namespace, a resource owned by another team, or infrastructure outside its resource group. Aspire 13.5 adds AsExistingInResourceGroup(...), AsExistingInSubscription(...), and AsExistingInTenant(...), plus run-mode and publish-mode variants.
var name = builder.AddParameter("service-bus-name");
var resourceGroup = builder.AddParameter("service-bus-resource-group");
var subscription = builder.AddParameter("service-bus-subscription");
builder.AddAzureServiceBus("messaging")
.AsExistingInResourceGroup(name, resourceGroup, subscription);
Names and scopes can be literal values or Aspire parameters, keeping environment details out of the AppHost source while references, configuration, and deployment intent stay in the model.
Easier than ever to get started with Homebrew, WinGet, and more
Over the last couple of months, we’ve expanded our release process to ship the Aspire CLI through Homebrew, WinGet, npm, Nix, mise, and NuGet! Now you can use your package manager of choice to install and update the Aspire CLI. aspire update --self still works, too, no matter where you originally installed the CLI.
Try Aspire 13.5
Update the CLI and your projects:
aspire update --self
aspire update
If you have an older TypeScript AppHost, aspire update --migrate can move apphost.ts to the current apphost.mts format.
Then, build out some features for command-driven file uploads, persistent Kubernetes-managed storage, or watch ASCII Star Wars in the refreshed dashboard.
New to Aspire?Install the CLI from your package manager of choice, and try the Aspireify skill on your existing apps.
CritterWatch will have its 1.0 release tomorrow (Wednesday, August 19th) just in time for a live stream on YouTube to show just the user interface part of CritterWatch. Today though, we finally got one last RC.10 release out for some much delayed feedback.
We made a large amount of changes to optimize performance based on early customer feedback as we jumped right into the deep end of the pool and started by integrating CritterWatch into literally the single biggest Critter Stack system that we’re aware of.
This release candidate basically got us to what I expect the final product to be for 1.0, minus some user interface feedback and polishing at the last minute.
CritterWatch will require you to be running basically the latest of everything:
Long day. Not done yet as I host my monthly all-hands calls in both AM and PM times to catch our global team. Fortunately these calls are fun, and it’ll distract me from a day of navigating corporate mazes.
[blog] AI usage patterns in software teams. Quite interesting data about the breadth of roles (and levels) using AI regularly. And what’s NOT changed.
[blog] AI Code Review Best Practices. Every team will do their own thing, but here are some viable techniques that work for this team.
[article] Nobody’s Actually Prioritising ‘Value’. Oooh, I like this take. “Value” is contextual to the recipient, and can only be measured after the value exchange occurs. We’re prioritizing work based on confidence in our hypotheses.
[article] A better approach to generative UI. Don’t just render out HTML/JS from your LLM. There’s all kinds of risk with that approach. Without saying so, this article makes the case for A2UI.
[article] A Home for Personal Context. Where does context live? Locally on a laptop? On the web? Or in your pocket? Probably all, in some way.
[blog] When the Hard Part Stops Being Hard. AI changes how long things take to do. We’re coming to grips with what that means to publication volume, research value, and our intellectual ambition.
[blog] Stop burning tokens on code review. It’s where you’re using the most tokens today in the SDLC. Use a cheaper (local?) model, create custom linters, or design this process with cost in mind.
The Mojo programming language has been promising an open source release since May 2023. Last week they shipped their 1.0 and today they have followed through on that original promise, releasing the compiler and toolchain under an Apache 2 license.
When Mojo first launched the stated goal was to produce a superset of Python, so existing Python code could be used to bootstrap their own ecosystem. That plan changed around August 2025:
Mojo may or may not evolve into a full superset of Python, and it’s okay if it doesn’t.
We’re encouraged by how well AI-assisted coding tools already help migrate Python to Mojo today, and we’re confident that future tooling and ecosystem maturity will make this evolution even smoother.
Today Mojo is its own language, optimized to make GPU programming as painless as possible using syntax inspired by Python, if not 100% compatible with existing code.