Workload Optimization · Houston, TX

Before you buy a bigger server, find out what's actually slow.

The quote for more cores usually arrives before anyone has profiled anything. Sometimes the hardware really is the constraint — but far more often it's one unindexed query, an N+1 loop, or a batch chain that has run serially since 2009 for no reason anybody remembers. Those don't get faster when you pay more. We measure first, then change one thing at a time.

Sound familiar?

Six complaints, and where the time usually goes

There is a usual cause behind each of these, and it is rarely the one the invoice is for.

The fix on the table is a bigger server

A quote for more cores arrives before anyone has profiled anything. Sometimes the hardware really is the constraint — but that should be a finding, not an assumption.

The overnight batch no longer fits overnight

It used to finish by four. Now it lands at seven, month-end lands later still, and somebody starts every morning checking whether yesterday actually closed.

One report brings the system to its knees

Everyone knows which one, and everyone knows to run it after hours. Nobody has ever looked at its query plan. That's a workaround the business quietly agreed to keep paying for.

The cloud bill grew and nothing changed

Instances sized during a panic two years ago are still running mostly idle, next to environments nobody has logged into since. Nobody owns the bill, so nobody asks what's on it.

It's slow, but only sometimes

Fine at ten, unusable at two. Intermittent is usually contention — blocking, a queue, or a scheduled job nobody has connected to the complaint yet.

The last upgrade bought less than the one before

Diminishing returns are the signature of a single-threaded step or a lock, not of a machine short on capacity. More cores cost real money and change nothing anybody notices.

Capabilities

Measure, change one thing, measure again

A baseline goes in writing before anything changes, and the same numbers get taken again at the end — including anything that got worse.

Profiling & Bottleneck Analysis

Measure before you change anything — otherwise it's a guess with a budget.

  • A written baseline: throughput, response times, batch durations, and today's cost
  • Application profiling and request tracing down to the specific slow call
  • Wait statistics and OS counters — CPU, memory, disk queue depth, network
  • N+1 queries, chatty interfaces, and exhausted connection pools found by evidence
  • Memory pressure and GC pauses separated from a genuine shortage of CPU

Database & Query Performance

Where most 'we need a bigger server' conversations quietly end.

  • Execution plans read properly — scans, spills, bad estimates, missing indexes
  • Indexes added where they earn their keep and dropped where they only cost writes
  • Statistics, parameter sniffing, and plan stability on the queries that matter
  • Locking and blocking traced back to the transaction that actually causes it
  • Archiving and partitioning when the table is simply too big to keep scanning

Batch, Jobs & Scheduling

For the overnight window that grew past the night.

  • Dependency chains mapped — what genuinely blocks what, and what only looks like it
  • Serial jobs run in parallel where the data allows, with the ordering proven safe
  • Restartability, so a failure at 3am doesn't mean rerunning eight hours of work
  • Full reloads replaced with incremental or delta processing where that's feasible
  • Schedules rebalanced so month-end stops colliding with the nightly run

Compute, Cloud & Licence Cost

Rightsizing, and switching off what nobody has opened in a year.

  • Instances rightsized against measured utilization, not the size someone guessed
  • Per-core and per-user licensing reviewed before anybody buys more cores
  • Reserved or committed capacity for the workloads that genuinely run all year
  • Idle environments, orphaned volumes, and forgotten test estates found and retired
  • Caching and query fixes priced against the hardware upgrade they would replace

Where tuning stops paying

Tuning has a ceiling, and it's worth naming up front. A large win on a job that runs monthly, overnight, with nobody waiting on it changes nothing anybody can feel — so work here gets ranked by its effect on the queue people are actually standing in, never by the size of the multiplier.

The other limit is work that shouldn't exist at all: the report with no readers, the approval step added after an incident in 2014, the file exported nightly so one person can ignore it. Waste that sits in the process rather than the code gets cleared more cheaply by a Lean Six Sigma pass. And where the design has genuinely run out of road, or the constraint lives inside a vendor product nobody can change, that goes into the report as the finding.

Where it pairs well

  • When a migration stalls because the new platform benchmarks slower than the old one
  • Integrations polling every thirty seconds for data that changes twice a day
  • WMS and TMS workloads — wave planning, rating calls, and the nightly inventory sync
  • Reports and ETL that got a little slower every year as the tables grew
  • Lean Six Sigma when the measurements point at a queue of people rather than a queue of jobs

No tests, no documentation?

Then tuning is the second job. Code rescue — a safe build, a safe deploy, and a net that catches regressions — is the first.

Slow Power BI is usually the model

Reports that crawl are far more often a semantic model problem than a capacity one. That's Power Platform work, not a hardware purchase.

Rewrites are the last resort

Occasionally the design really has run out of road. We'll say so — and build the replacement only if the measurements justify it.

What this looks like in practice

Our project write-ups cover what the constraint turned out to be and what changed — without the client logos.

Toolkit

What we work in

Execution plans SQL Server Query Store Extended Events & Profiler Index tuning Statistics & parameter sniffing Blocking & deadlock traces PostgreSQL EXPLAIN ANALYZE pg_stat_statements MySQL slow query log Oracle AWR & Statspack Wait statistics Table partitioning Archiving & purge strategies Python cProfile & py-spy Application tracing N+1 query detection Redis & application caching Connection pooling k6 & JMeter load testing Linux perf, top & iostat Windows Performance Monitor cron & SQL Agent jobs Control-M & Autosys Incremental & delta processing Azure & AWS cost tooling Instance rightsizing Reserved & committed capacity Per-core licence review
Questions we get

Straight answers

Our system is slow. Should we just buy a bigger server?

Maybe — but that should be a conclusion, not an opening move. Hardware fixes a genuine shortage of capacity. It does very little for a missing index, a lock, or a batch chain that runs serially for no reason, because none of those scale with cores. We measure first and tell you which one you have, and when the hardware really is the constraint you get that in writing too.

What if the honest answer is that we don't need you?

Then you get told that. If the constraint is inside a vendor product nobody can change, if the design is already close to what it can do, or if the slow thing runs once a month while nobody waits on it, there is no engagement worth selling you. Saying that costs us a project and saves you one, which is the trade we would rather make.

How do you prove it actually got faster?

The same measurement, taken before and after, over the same workload. We record the baseline first — batch durations, query times, throughput, and where it matters the monthly bill — and the closing document compares against it, including anything that got worse. Without that pair of numbers, nobody can tell tuning apart from luck.

Can you work on a system you didn't build?

That's most of what we do. We start from the running system — its plans, logs, counters, and schedule — rather than from documentation that may not exist. If the code turns out to be genuinely unsafe to change, with no tests and one person who half-remembers it, that's a code rescue problem first and we'll say so before touching anything.

Will you need to change our application code?

Often less than you'd expect. A good share of the wins sit outside the code: an index, a schedule change, a config setting, a connection pool sized for a smaller world. Where code does have to change — an N+1 query, a chatty interface, a cache that was never there — we keep the change small and reversible, and it goes through your normal review and release process.

Our cloud bill is the problem, not speed.

Then we start at the bill. Rightsizing against measured utilization, reserved capacity for what genuinely runs year-round, and a hunt for the environments, volumes, and licences nobody has touched since the person who created them left. Worth remembering that the cheapest optimization is deleting work nobody needed: before tuning a report, check who still reads it.

Name the job everybody schedules around.

How long does it take today, and who is standing around waiting on it? We'll say where the time is probably going, and what measuring it properly would take.

Start the conversation