Performance: Batch the content cache delete on structural content type changes - #23329
Conversation
|
Claude finished @AndyButland's task in 4m 52s —— View job PR ReviewTarget: Replaces the single unbounded
Suggestions
Approved with Suggestions for improvementGood to go — the approach is well-reasoned (stable-table ID fetch, configurable batch size, safety cap, per-batch logging, good integration test), and no breaking changes. Please do a manual sanity check before merging. |
There was a problem hiding this comment.
Pull request overview
Improves the hybrid published cache rebuild path for structural content type changes by replacing a single large DELETE against cmsContentNu with a predictable batched delete, reducing transaction log pressure and lock escalation risk on large datasets.
Changes:
- Introduces batched deletion of
cmsContentNurows bynodeIdduring rebuilds, with per-batchexecuteStepexecution for deferred rebuild transaction boundaries. - Adds
NuCacheSettings.ContentTypeRebuildDeleteBatchSize(default 2000, capped toConstants.Sql.MaxParameterCount) to control delete batch sizing. - Adds an integration test that marks existing cache rows as stale and verifies a rebuild removes stale rows and fully repopulates cache rows for the affected content type.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/Umbraco.Tests.Integration/Umbraco.PublishedCache.HybridCache/DatabaseCacheRepositoryTests.cs | Adds an integration test and config override to exercise and validate the new batched delete behavior during rebuild. |
| src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs | Replaces single unbounded deletes with a new batched-delete helper used by content/media/member rebuild paths. |
| src/Umbraco.Core/Configuration/Models/NuCacheSettings.cs | Adds a new configuration option for delete batch size with documentation and default value. |
|
|
Docs PR is here: umbraco/UmbracoDocs#8235 |



Description
Follow-up to the investigation into SQL command timeouts when saving a structural change to a document type (e.g. removing a property) that backs a lot of content.
When a content type changes structurally, the published cache (
cmsContentNu) is rebuilt for every affected document. The first step of that rebuild deleted all of the type's rows in a single, unboundedDELETE. On sites with a lot of content those rows carry large LOB columns (dataNVARCHAR(MAX),dataRawVARBINARY), so the one statement generates heavy transaction-log I/O, can escalate to a table lock, and — as seen on a customer install — can exceed even a raisedCommandTimeout, rolling the whole save back.This PR replaces that single delete with a batched delete:
cmsContentNurows are deleted in batches by clustered primary key (nodeId). This deliberately avoids re-scanning the source per batch, so it stays predictable even without acontentTypeIdindex.executeStepdelegate, so underContentTypeRebuildMode.Deferredeach batch commits in its own transaction — releasing its locks and log space between batches instead of accumulating across the whole delete. Under the immediate path the batches share the ambient transaction, but eachDELETEstatement is still individually bounded.NuCacheSettings.ContentTypeRebuildDeleteBatchSize(default 2000, capped at the SQL parameter limit). It sits next toSqlPageSize, which governs the insert/repopulation paging of the same rebuild.SELECT COUNT(*)step is removed.DebugforUmbraco.Cms.Infrastructure.HybridCache.Persistence.DatabaseCacheRepository).The full-clear path (a full cache rebuild, where the table has typically already been truncated) is unchanged and remains a single statement.
This is a self-contained improvement and pairs with the separately-submitted index on
umbracoContent(contentTypeId)in #23328.Testing
Automated
An integration test covering multi-batch deletion has been added.
Manual
With
ContentTypeRebuildMode: Deferredand a smallContentTypeRebuildDeleteBatchSize(e.g. 5), make a structural change to a document type that has several content items and watch the debug log — the rebuild deletes the rows in batches, each committed independently, e.g.: