Skip to content
Back to skills

Sql Index Maintenance

ASecurity

Reviews ongoing SQL Server index/statistics maintenance as an operational concern distinct from sql-performance-review's query-level analysis. Flags no scheduled job rebuilding/reorganizing fragmented indexes, no statistics-update cadence for tables with volatile data, no monitoring for unused indexes accumulating write overhead, and no maintenance-window awareness for online vs offline index operations. Outputs findings with pilot-sql index-maintenance standard IDs.

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 6, 2026
developmentgosqlazuredatabaseperformance

Security analysis

A100/100

Scanned September 6, 2026

npx -y skills add AgenticPawan/FullStack-Pilot --skill sql-index-maintenance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sql Index Maintenance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sql Index Maintenance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/agenticpawan-sql-index-maintenance/badge)](https://www.skillsdirectory.com/skills/agenticpawan-sql-index-maintenance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sql-index-maintenance
description: Reviews ongoing SQL Server index/statistics maintenance as an operational concern distinct from sql-performance-review's query-level analysis. Flags no scheduled job rebuilding/reorganizing fragmented indexes, no statistics-update cadence for tables with volatile data, no monitoring for unused indexes accumulating write overhead, and no maintenance-window awareness for online vs offline index operations. Outputs findings with pilot-sql index-maintenance standard IDs.
when_to_use: index fragmentation, index rebuild, index reorganize, statistics update, sp_updatestats, unused index, maintenance window, ONLINE index operation, index maintenance job, sys.dm_db_index_physical_stats
---

## Standard IDs

| ID | Severity | What it checks |
|----|----------|-----------------|
| IDX-001 | P1 | No scheduled job rebuilding/reorganizing fragmented indexes |
| IDX-002 | P1 | No statistics-update cadence for tables with volatile data |
| IDX-003 | P2 | No monitoring for unused indexes accumulating write overhead |
| IDX-004 | P2 | No maintenance-window awareness for online vs offline index operations |

`sql-performance-review` reviews individual queries (SARGability, missing indexes for a
specific access pattern); this skill governs the ongoing operational health of indexes
that already exist — a good index recommendation degrades over time without maintenance.

---

## Check A — No scheduled fragmentation maintenance (IDX-001)

### Detection

Check for a scheduled job (SQL Agent job, Hangfire job per `dotnet-background-jobs`, or
Azure SQL's built-in automatic tuning) that rebuilds/reorganizes indexes once
fragmentation crosses a threshold. Without one, indexes fragment over time as rows are
inserted/updated/deleted, and query performance degrades gradually with no single event
to point to — it just gets slower every month until someone investigates.

### BAD — no maintenance job, fragmentation grows unchecked

```sql
-- No scheduled job anywhere queries sys.dm_db_index_physical_stats or acts on it.
-- Query plans that were fine at launch are 40% slower a year later with no alert fired.
```

### GOOD — a scheduled job applying the standard fragmentation thresholds

```sql
-- Runs weekly via SQL Agent (or a Hangfire recurring job, per dotnet-background-jobs)
SELECT s.name AS SchemaName, t.name AS TableName, i.name AS IndexName, ps.avg_fragmentation_in_percent
INTO #FragmentedIndexes
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ps
JOIN sys.indexes i ON ps.object_id = i.object_id AND ps.index_id = i.index_id
JOIN sys.tables t ON i.object_id = t.object_id
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE ps.avg_fragmentation_in_percent > 5 AND ps.page_count > 1000;

-- 5-30% fragmented: REORGANIZE (online, low-impact)
-- >30% fragmented: REBUILD (prefer WITH (ONLINE = ON) — see Check D)
```

---

## Check B — No statistics-update cadence (IDX-002)

### Detection

Check whether `AUTO_UPDATE_STATISTICS` is relied on alone for tables with high write
volume/volatile data distribution, versus a scheduled `UPDATE STATISTICS`/
`sp_updatestats` run proactively. SQL Server's auto-update triggers only after ~20% of
rows change (by default), which on a large, fast-growing table can mean stats go stale
for a long stretch — leading the query optimizer to pick a plan based on outdated
row-count estimates.

### BAD — relying solely on the auto-update threshold for a high-volume table

```sql
-- Orders table: 50M rows, growing 500K/day. AUTO_UPDATE_STATISTICS default threshold
-- means stats can be significantly stale for days before the ~20% change trigger fires.
```

### GOOD — proactive statistics refresh scheduled alongside the fragmentation job

```sql
-- Runs nightly for high-volatility tables identified in the maintenance plan
UPDATE STATISTICS dbo.Orders WITH FULLSCAN;
-- Or, for a full-database sweep on a maintenance window:
EXEC sp_updatestats;
```

---

## Check C — No monitoring for unused indexes (IDX-003)

### Detection

Check for a periodic query against `sys.dm_db_index_usage_stats` identifying indexes with
high write cost (`user_updates`) but near-zero read benefit (`user_seeks` +
`user_scans` + `user_lookups`) — an unused index still pays its full write-amplification
cost on every insert/update/delete with zero query benefit, and accumulates silently as
features get built and torn down over a codebase's lifetime.

### BAD — indexes accumulate over years, nobody ever audits which are still used

```sql
-- No periodic review of sys.dm_db_index_usage_stats — every index ever created for a
-- feature that's since been removed is still slowing down every write to that table.
```

### GOOD — a periodic audit query flags write-only indexes for review

```sql
SELECT OBJECT_NAME(s.object_id) AS TableName, i.name AS IndexName,
       s.user_seeks + s.user_scans + s.user_lookups AS ReadsUsed, s.user_updates AS WritesCost
FROM sys.dm_db_index_usage_stats s
JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id
WHERE s.database_id = DB_ID()
  AND (s.user_seeks + s.user_scans + s.user_lookups) = 0
  AND s.user_updates > 1000
ORDER BY s.user_updates DESC;
-- Candidates for removal — confirm no seasonal/quarterly report depends on them first.
```

---

## Check D — No maintenance-window awareness (IDX-004)

### Detection

Check whether index rebuilds run `WITH (ONLINE = ON)` (Enterprise/Azure SQL) or are
explicitly scheduled during a low-traffic maintenance window for editions without online
rebuild support. An offline `ALTER INDEX ... REBUILD` takes a blocking schema
modification lock for the duration of the rebuild — running one against a large table
during business hours causes a very real, very avoidable outage.

### BAD — offline rebuild run with no regard for traffic patterns

```sql
ALTER INDEX IX_Orders_CustomerId ON dbo.Orders REBUILD;
-- Run at 2pm on a weekday against a 200M-row table — blocks every concurrent read/write
-- for the rebuild's duration, taking down checkout for the affected time window.
```

### GOOD — online rebuild, or scheduled during a documented low-traffic window

```sql
ALTER INDEX IX_Orders_CustomerId ON dbo.Orders REBUILD WITH (ONLINE = ON, MAX_DURATION = 60 MINUTES);
```

```markdown
<!-- For editions without ONLINE rebuild support -->
Maintenance window: Sundays 02:00–04:00 UTC, documented in docs/DR-PLAN.md alongside
the RPO/RTO targets azure-dr-multiregion already tracks.
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…