Skip to content

Commit acefc56

Browse files
Docs: per-database grants for FinOps Index Analysis (#915)
* Docs: per-database grants for FinOps Index Analysis (#915) Adds a Permissions subsection covering the per-user-database mapping + VIEW DATABASE STATE + VIEW DEFINITION grants that sp_IndexCleanup needs to avoid hanging at 100% CPU when the dashboard/Lite login lacks access to a target database. Includes a single-DB block and an sp_MSforeachdb helper, plus the engine-bug explanation (infinite recompile loop, not sys.dm_db_partition_stats per se). Adds a matching troubleshooting entry naming the hang symptom and linking to the new section. * Docs: add SELECT on sys.sql_expression_dependencies grant (#915) Earlier permissions block was incomplete. VIEW DATABASE STATE + VIEW DEFINITION are necessary but not sufficient: sp_IndexCleanup also queries sys.sql_expression_dependencies via three-part name when scanning for computed columns / check constraints with UDF references, and SELECT on that catalog view defaults to db_owner only. VIEW DEFINITION does not include it. OP confirmed in the issue thread that the previous grant set still yielded Msg 229 on a real workload database. Reproduced locally on SQL2019 with a database containing a UDF-bound computed column and check constraint; adding GRANT SELECT ON sys.sql_expression_dependencies clears it. Run completes in <1s and returns the expected UDF rows. Updates: - Single-DB and sp_MSforeachdb blocks now include the third grant. - Symptoms section split into the two distinct failure modes (hang vs. Msg 229) so readers can identify which grant they are missing. - Troubleshooting bullet covers both symptoms. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b9b495a commit acefc56

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ Common issues:
539539
2. **Query Store tab empty** — Query Store must be enabled on the target database (`ALTER DATABASE [YourDB] SET QUERY_STORE = ON`).
540540
3. **Blocked process reports empty** — Both editions attempt to auto-configure the blocked process threshold to 5 seconds via `sp_configure`. On **AWS RDS**, `sp_configure` is not available — you must set `blocked process threshold (s)` through an RDS Parameter Group (see "AWS RDS Parameter Group Configuration" above). On **Azure SQL Database**, the threshold is fixed at 20 seconds and cannot be changed. If you still see no data on other platforms, verify the login has `ALTER SETTINGS` permission.
541541
4. **Connection failures** — Verify network connectivity, firewall rules, and that the login has the required [permissions](#permissions). For Azure SQL Database, use a contained database user with `VIEW DATABASE STATE`.
542+
5. **FinOps Index Analysis hangs, times out, or returns `Msg 229` on `sql_expression_dependencies`**`sp_IndexCleanup` runs against each user database under your dashboard/Lite login. If that login has no user mapping in a target database, the procedure can hang at 100% CPU instead of erroring; if it is mapped but missing `SELECT` on `sys.sql_expression_dependencies`, it errors immediately on databases that have UDF-bound computed columns or check constraints. See [FinOps Index Analysis](#finops-index-analysis-per-database-grants) below for the full per-database grant set that fixes both.
542543

543544
---
544545

@@ -589,6 +590,44 @@ CREATE USER [YourLogin] FOR LOGIN [YourLogin];
589590
ALTER ROLE [SQLAgentReaderRole] ADD MEMBER [YourLogin];
590591
```
591592

593+
### FinOps Index Analysis (per-database grants)
594+
595+
Applies to **both editions**. The FinOps Index Analysis tab runs `sp_IndexCleanup` against each user database you ask it to inspect, executing as your dashboard/Lite login. The grants above (`VIEW SERVER STATE`, `db_owner` on `PerformanceMonitor`, `SQLAgentReaderRole` on `msdb`) are *not* sufficient on their own — the login also needs a user mapping in every user database it will analyze, plus `VIEW DATABASE STATE`, `VIEW DEFINITION`, and `SELECT` on `sys.sql_expression_dependencies` in each.
596+
597+
The third grant is the easy one to miss: by default only members of `db_owner` have `SELECT` on `sys.sql_expression_dependencies`, and `VIEW DEFINITION` does not include it. `sp_IndexCleanup` queries that catalog view (via three-part name to the target database) when checking for computed columns and check constraints that reference UDFs, so the failure only surfaces on databases that actually have those — which is why a smoke-test database may pass and a real workload database fails with `Msg 229`.
598+
599+
For each target user database:
600+
601+
```sql
602+
USE [YourTargetDatabase];
603+
CREATE USER [SQLServerPerfMon] FOR LOGIN [SQLServerPerfMon];
604+
GRANT VIEW DATABASE STATE TO [SQLServerPerfMon];
605+
GRANT VIEW DEFINITION TO [SQLServerPerfMon];
606+
GRANT SELECT ON sys.sql_expression_dependencies TO [SQLServerPerfMon];
607+
```
608+
609+
Or apply broadly with `sp_MSforeachdb`:
610+
611+
```sql
612+
EXEC sp_MSforeachdb N'
613+
USE [?];
614+
IF DB_ID() > 4 AND DATABASEPROPERTYEX(DB_NAME(), ''Updateability'') = ''READ_WRITE''
615+
BEGIN
616+
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = ''SQLServerPerfMon'')
617+
CREATE USER [SQLServerPerfMon] FOR LOGIN [SQLServerPerfMon];
618+
GRANT VIEW DATABASE STATE TO [SQLServerPerfMon];
619+
GRANT VIEW DEFINITION TO [SQLServerPerfMon];
620+
GRANT SELECT ON sys.sql_expression_dependencies TO [SQLServerPerfMon];
621+
END';
622+
```
623+
624+
**Symptoms if missing.** There are two distinct failure modes depending on which grant is absent:
625+
626+
- *No user mapping in the target database*`sp_IndexCleanup` can hang at 100% CPU with no waits and never return, instead of failing fast with `Msg 916` like every other catalog DMV. The hang isn't a deadlock or a long-running scan; it's a SQL Server engine bug where a permission check at execute time gets misclassified as "this plan needs to be recompiled," producing an infinite recompile loop. Reproduces on SQL Server 2016 SP3 through 2025 CU4.
627+
- *User is mapped with `VIEW DATABASE STATE` + `VIEW DEFINITION` but no `SELECT` on `sys.sql_expression_dependencies`* — fails fast with `Msg 229, Level 14, State 5: The SELECT permission was denied on the object 'sql_expression_dependencies', database 'mssqlsystemresource', schema 'sys'` the moment a database with a UDF-bound computed column or check constraint is reached.
628+
629+
Adding all three grants above eliminates both. See issue [#915](https://github.com/erikdarlingdata/PerformanceMonitor/issues/915) for the full diagnosis.
630+
592631
### Azure SQL Database (Lite Only)
593632

594633
Azure SQL Database doesn't support server-level logins. Create a **contained database user** directly on the target database:

0 commit comments

Comments
 (0)