APM Tips

KQL · dependencies

Slowest dependencies by target

The 20 dependency targets with the worst p95 call duration in the last 24 hours, with call volume and failures, sampling-adjusted.

Updated

dependencies dependencies

let lookback = 24h;
dependencies
| where timestamp > ago(lookback)
| summarize
    calls = sum(itemCount),
    p95_ms = percentilew(duration, itemCount, 95),
    failed = sumif(itemCount, tostring(success) =~ "false")
    by type, target
| order by p95_ms desc
| take 20

Returns: Up to 20 rows, one per dependency type and target, with the call count, the p95 duration in milliseconds and the number of failed calls, slowest first.

Pitfalls

  • target is what the SDK recorded as the destination: a host name for HTTP, server and database for SQL. Calls through a proxy or a shared gateway all land on the gateway's name.
  • Weight percentiles and counts by itemCount; with sampling on, each row stands for several calls.
  • A slow dependency is not always the cause of a slow request. Check whether the calls sit on the request's critical path or run in parallel before blaming the target.
  • Low-volume targets can top a p95 list with a single slow call. Add | where calls > 50 to rank only busy targets.

How it works

The dependencies table holds one row per outgoing call your app recorded: HTTP calls to other services, SQL queries, queue and storage operations. Grouping by type and target turns thousands of rows into a short list of the things your app waits on, ranked by how slow they are for the worst 5% of calls.

Keeping type in the grouping matters. The same host can appear as an HTTP target and as a different kind of dependency, and their latency profiles have nothing in common.

Reading the result

Look at p95_ms and calls together. A target with a high p95 and high volume is costing time on many requests; it is the first candidate for caching, batching or a timeout review. A target with a high p95 and a high failed count often means timeouts: the call waits for the full timeout and then fails, which drags the percentile up.

Next step: which operations wait on it

Once a target stands out, find the requests that call it:

dependencies
| where timestamp > ago(24h)
| where target == "orders-db.example.net"
| summarize calls = sum(itemCount), p95_ms = percentilew(duration, itemCount, 95) by operation_Name
| order by calls desc

Variations

  • Only failures: add | where tostring(success) =~ "false" before the summarize and group by resultCode as well.
  • Workspace tables: use AppDependencies, TimeGenerated, DependencyType, Target, DurationMs, Success and ItemCount.

A dependency you know your app calls but can’t find here wasn’t recorded at all; the agent-based dependency tracking guide explains which calls each collection method sees.

Sources, checked

  1. Migrate an Application Insights classic resource to a workspace-based resource (table schemas)learn.microsoft.com · checked
  2. percentilew(), percentilesw() (Kusto)learn.microsoft.com · checked
  3. sumif() (Kusto)learn.microsoft.com · checked
  4. Telemetry sampling in Application Insightslearn.microsoft.com · checked