Files
ScadaBridge/docs/plans/2026-11-13-auditlogentries-index-usage.md
T

4.5 KiB

AuditLogEntries index usage: first measurement (2026-11-13)

Tracks: Gitea ScadaBridge#70 (deferred-work register row 135). Question: are the single-column IX_AuditLogEntries_Timestamp, _User and _EntityType indexes dead weight now that ReviewRemediationIndexes added (EntityType, Timestamp DESC), (User, Timestamp DESC) and (Timestamp DESC, Id DESC)?

Decision: no migration yet. The measurement window is too short on both tiers, and no index on the table was read at all, the new composites included. Re-measure on or after 2026-11-27.

Method

Read-only SELECTs over a direct SQL login (sqlcmd -C), no remote exec, run 2026-11-13 ~02:10 server time: sys.dm_db_index_usage_stats LEFT JOIN sys.indexes for dbo.AuditLogEntries, plus sys.dm_db_index_operational_stats, sys.partitions/sys.allocation_units for rows and size, and sys.dm_os_sys_info.sqlserver_start_time (the DMVs reset when SQL Server restarts).

Measurement window

Tier SQL host / DB sqlserver_start_time Window Latest migration
DEV wonder-app-vd03 / ScadaBridge 2026-11-10 06:42 ~3 days 20261110120000_AuditMaintenanceGrants (64)
QA wonder-sql-vq03 / ScadaBridge 2026-11-03 07:09 ~10 days 20261022133907_ReviewRemediationIndexes (58)

Both are under the two weeks needed. The migration went in on 2026-10-22, but SQL restarts since then have reset the counters.

Results

Table size: DEV 471 rows (Timestamp 2026-05-29 to 2026-10-28), QA 567 rows (to 2026-11-06).

Index Keys DEV seeks/scans/lookups DEV updates QA seeks/scans/lookups QA updates Size
PK_AuditLogEntries (clustered) Id 0/0/0 0 0/0/0 10 1.4 MB / 4.3 MB
IX_AuditLogEntries_Action Action 0/0/0 0 0/0/0 10 72 KB
IX_AuditLogEntries_EntityId EntityId 0/0/0 0 0/0/0 10 72 KB
IX_AuditLogEntries_EntityType EntityType 0/0/0 0 0/0/0 10 72 KB
IX_AuditLogEntries_Timestamp Timestamp 0/0/0 0 0/0/0 10 72 KB
IX_AuditLogEntries_User User 0/0/0 0 0/0/0 10 72 KB
IX_AuditLogEntries_BundleImportId BundleImportId 0/0/0 0 0/0/0 10 72 KB
IX_AuditLogEntries_EntityType_Timestamp EntityType, Timestamp DESC 0/0/0 0 0/0/0 10 200 KB
IX_AuditLogEntries_Timestamp_Id Timestamp DESC, Id DESC 0/0/0 0 0/0/0 10 200 KB
IX_AuditLogEntries_User_Timestamp User, Timestamp DESC 0/0/0 0 0/0/0 10 200 KB
IX_AuditLogEntries_EntityName (DEV only, migration 59+) EntityName 0/0/0 0 — — 200 KB

sys.dm_db_index_operational_stats agrees: zero range scans and singleton lookups on every index on both tiers, with 10 leaf inserts per index on QA and none on DEV.

Reading

  • The data does not settle the question. Every index reads zero, including the composites that are supposed to replace the single-column ones. Nobody used the config-audit page or the CLI query on either tier during the window, and the purge job did not touch the table. A zero on an old index only means something if the composite that replaces it shows reads.
  • On write cost: the table is tiny (about 500 rows) and takes about 1 write a day on QA. The three single-column indexes cost about 216 KB and 3 extra index writes per insert. Nothing is urgent.
  • Static coverage (from code, not from the measurement): each single-column index is a left prefix of a composite. The filters in CentralUiRepository (User ==, EntityType ==, Timestamp range, ordered by Timestamp DESC, Id DESC) and the purge in ConfigAuditPurgeService (Timestamp < cutoff ORDER BY Timestamp, which can use a backward scan of IX_AuditLogEntries_Timestamp_Id) are all served by the composites. So the case for dropping the three indexes is sound in principle. The register's rule is "measured, not assumed", and this run measured nothing useful.

Next step

Re-run the same query on or after 2026-11-27, which is two weeks after both current sqlserver_start_times. Check sqlserver_start_time again first. If the composites show reads and the single-column indexes still show zero, drop IX_AuditLogEntries_Timestamp, _User and _EntityType in one migration whose Down() recreates them. Leave Action, EntityId, BundleImportId and EntityName alone, because no composite covers them. If every index still reads zero, the owner has to decide whether to drop on static grounds or to exercise the config-audit page on QA first and then measure.