Skip to content

Analyst queries

Ready-to-paste KQL for the KQL query editor, from fabric/kql/03_queries.kql. These are ad-hoc — they are not part of provisioning.

The triple, most recent first

FdaInteractions
| order by Timestamp desc
| project Timestamp, User, Question, GeneratedDax, ExecutedDax, Answer, Status, DurationMs, MatchConfidence
| take 100

Pipeline health — are we capturing & correlating?

FdaInteractions
| summarize Total=count(),
            WithQuestion=countif(isnotempty(Question)),
            WithDax=countif(isnotempty(ExecutedDax)),
            WithAnswer=countif(isnotempty(Answer)),
            Unmatched=countif(MatchConfidence=="Unmatched")
        by bin(Timestamp, 1h)
| order by Timestamp desc

A healthy pipeline shows most rows with question, DAX, and answer populated, and a low Unmatched count.

Source coverage — which surfaces are feeding us

FdaInteractions
| mv-expand Source = Sources to typeof(string)
| summarize Interactions=count() by Source, bin(Timestamp, 1d)
| order by Timestamp desc

If monitoring is present but graph is missing, you're getting DAX without question/answer text (check the Graph user set / permissions). If graph is present but monitoring is missing, check workspace monitoring.

Tuning — slowest generated DAX

FdaInteractions
| where isnotempty(ExecutedDax)
| top 50 by DurationMs desc
| project Timestamp, User, DurationMs, CpuTimeMs, Question, ExecutedDax

Tuning — failing questions

FdaFailures(ago(7d), now())

NL2DAX errors / empty results / unmatched rows — the review backlog. See FdaFailures.

Tuning — top question patterns

FdaTopQuestions(ago(30d), now(), 50)

The highest-volume normalized questions — prime candidates to add as FDA example queries. See FdaTopQuestions.

Raw executed DAX (debug correlation gaps)

Raw_ExecutedDax
| where Timestamp > ago(1d) and isnotempty(Dax)
| project Timestamp, ExecutingUser, SemanticModelName, DurationMs, CpuTimeMs, Status, Dax
| order by Timestamp desc
| take 100

Use this when curated rows are Unmatched — confirm the DAX is arriving from monitoring, then check the user / time-window join.

SDK replay vs production

Raw_SdkRuns
| where ReplayedAt > ago(7d)
| extend QNorm = trim(@"\s+", tolower(Question))
| join kind=leftouter (
    FdaInteractions
    | where isnotempty(Question)
    | extend QNorm = trim(@"\s+", tolower(Question))
    | summarize arg_max(Timestamp, ExecutedDax) by QNorm
  ) on QNorm
| project Question, SdkStatus=Status, SdkGeneratedQueries=GeneratedQueries,
          ProdExecutedDax=ExecutedDax
| take 100

Compares the SDK replay reconstruction to what M365 actually executed.

Did a specific user's question get a DAX match?

let u = "user@contoso.com";
Raw_GraphInteractions
| where User == u and InteractionType == "userPrompt"
| project PromptTime=CreatedDateTime, Question=Body
| join kind=leftouter (
    Raw_ExecutedDax | where ExecutingUser == u | project DaxTime=Timestamp, Dax
  ) on $left.PromptTime == $right.DaxTime
| project PromptTime, Question, DaxTime, Dax
| order by PromptTime desc

A per-user correlation spot-check straight against the raw tables.

Quick verification (after first run)

FdaInteractions | take 50
FdaInteractions | summarize count() by MatchConfidence, bin(Timestamp, 1h)

If FdaInteractions has rows with GeneratedDax populated and MatchConfidence != "Unmatched", the pipeline works.