nav2009-sql-performance
Diagnose performance problems in Microsoft Dynamics NAV 2009 (Navision) and its SQL Server database. The bundled script collects a read-only DMV snapshot (top queries, waits, blocking, deadlocks, miss
SKILL.mdskills/nav-2009/nav2009-sql-performance/SKILL.md
GitHubNAV 2009 SQL Performance Triage
Targets SQL Server instances hosting Dynamics NAV 2009 databases. The bundled script
scripts/Invoke-SqlPerfTriage.ps1collects a read-only diagnostic snapshot and emits JSON; the agent (you) writes the analysis. The script never modifies server or database state and never calls an LLM.
SCRIPT = this skill's scripts/Invoke-SqlPerfTriage.ps1. Requires PowerShell 7+ (pwsh)
and network access to the SQL Server. The full SQL-finding → NAV-action interpretation guide is in
REFERENCE.md — read it before writing your analysis.
Permissions & auth
- Default is Windows integrated auth (the user running
pwsh). Pass-SqlCredentialfor SQL auth — it is aPSCredential, so let PowerShell prompt (-SqlCredential (Get-Credential)); never put a password on the command line. - Needs VIEW SERVER STATE on the instance and VIEW DATABASE STATE (or
db_owner) in the NAV database. The trace-flag sub-check may need sysadmin and degrades gracefully if denied. - Connections are unencrypted by default (NAV 2009-era instances rarely have TLS certs); add
-Encryptif the instance supports it.
How to run
Always run with pwsh. Parse the JSON it prints on stdout.
| Want | Pass |
|---|---|
| Full snapshot of a NAV DB | -ServerInstance SQLSRV01 -Database 'NAV_PROD' |
| Named instance | -ServerInstance 'SQLSRV01\NAV' |
| Server-level only (no DB) | omit -Database (DB-scoped sections report skipped) |
| Only some sections | -Sections waits,blocking,deadlocks |
| SQL auth | -SqlCredential (Get-Credential) |
| Bigger/smaller lists | -TopN 20 (default) |
| Slow big DB | -QueryTimeout 300 (fragmentation scan is the slow one; or drop it from -Sections) |
| Save full report | -OutFile C:\path\triage.json |
Sections: server, database, waits, top_queries, missing_indexes, unused_indexes,
blocking, deadlocks, sift, fragmentation, stats, largest_tables (default all).
Examples:
# Full triage of a NAV 2009 database
pwsh -File SCRIPT -ServerInstance SQLSRV01 -Database 'Navision_PROD' -OutFile C:\ops\nav-triage.json
# "Users are stuck right now" — live locking picture only
pwsh -File SCRIPT -ServerInstance SQLSRV01 -Database 'Navision_PROD' -Sections blocking,deadlocks,waits
Output contract
- Without
-OutFile→ full JSON on stdout. - With
-OutFile→ full JSON to the file; a compact summary (per-section status + row counts) on stdout. Prefer-OutFilefor full snapshots so your context stays small; then read only the sections you need from the file.
Top level: status (ok / partial / error), generated_at (UTC), and sections, where each
section is { status: ok|error|skipped, data|error|reason }. Timestamps inside data are SQL
Server local time; deadlock timestamps are UTC. Full schema and per-section notes in
REFERENCE.md.
What you (the agent) do with the result
- Run the script, parse the JSON.
- Interpret through the NAV lens, not just generic SQL tuning — use the mapping table in
REFERENCE.md. The key NAV 2009 specifics:
- Top queries full of
FETCH API_CURSOR/sp_cursorfetchare normal for the Classic client driver — judge them by reads-per-execution, not by their cursor shape. - High reads-per-execution usually traces back to C/AL: missing
SETCURRENTKEYmatching the filters,FIND('-')loops over large tables, orCALCSUMS/FlowFields without a supporting SIFT key. The fix belongs in C/AL or NAV key design more often than in raw SQL indexes. - Never recommend creating/dropping indexes directly in SQL on a NAV 2009 DB as the first
option — NAV owns its indexes via table keys (
MaintainSQLIndex) and SIFT views (MaintainSIFTIndex); out-of-band SQL indexes are lost when keys/companies change. Say so. - Blocking/deadlocks during posting: look at the objects involved (
G/L Entry,Item Ledger Entry, dimension tables,No. Series Line) — typical fixes are C/AL-side (lock ordering, shorter transactions,MaintainSIFTIndexoff on hot SIFT views), not SQL-side.
- Top queries full of
- Lead with the 2–4 findings that matter, each as: evidence (numbers from the JSON) → likely NAV-level cause → concrete next action. Don't recite every section.
- Fail loud on coverage: name any section with
status: error/skippedand what that means for the analysis (e.g. "deadlocks section unavailable — SQL 2005 has no Extended Events"). Wait stats and index usage are cumulative since instance restart — state the window (server.system.sqlserver_start_time) before drawing conclusions from them. - For the C/AL side of a finding (which key to add, how to restructure a loop), the nav2009-development skill holds the coding patterns.
Errors
Cannot connect→ wrong instance name, SQL Browser off for named instances, firewall, or auth. Suggest checking withTest-NetConnection <server> -Port 1433.- Section
error: VIEW SERVER STATE permission was denied→ ask for the permission grant; the remaining sections still ran. deadlocksempty/unsupported on SQL Server 2005 → only SQL Profiler / trace flag 1222 can capture deadlocks there; offer that as the manual alternative.