Skip to content

Performance: Add index on umbracoContent.contentTypeId - #23328

Merged
Zeegaan merged 1 commit into
v17/devfrom
v17/improvement/add-index-for-content-content-type
Jul 12, 2026
Merged

Performance: Add index on umbracoContent.contentTypeId#23328
Zeegaan merged 1 commit into
v17/devfrom
v17/improvement/add-index-for-content-content-type

Conversation

@AndyButland

@AndyButland AndyButland commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description

Adds a non-clustered index on umbracoContent(contentTypeId).

The column has a foreign key to cmsContentType but no supporting index. SQL Server does not automatically index foreign key columns, so any query that filters or joins on umbracoContent.contentTypeId has to scan the table.

That column is on the hot path for content-type-scoped operations — most notably the published cache (cmsContentNu) rebuild that runs when a document type changes structurally (e.g. a property is removed). That rebuild's delete, row count, and paged node-id selection all filter content by content type via this column:

DELETE FROM [cmsContentNu]
WHERE [nodeId] IN (
    SELECT [umbracoNode].[id]
    FROM [umbracoNode]
    INNER JOIN [umbracoContent] ON [umbracoNode].[id] = [umbracoContent].[nodeId]
    WHERE [umbracoNode].[nodeObjectType] = @0 AND [umbracoContent].[contentTypeId] IN (@1))

On sites with a large amount of content this scan is a measurable contributor to slow content-type saves (and, in the worst cases, to the SQL command timeouts some customers hit when editing a document type that backs a lot of content). The index lets these queries seek rather than scan.

How it works

  • New installs — the index is declared on ContentDto.ContentTypeId (IX_umbracoContent_contentTypeId), so the schema creator builds it from the DTO like every other index.
  • Upgrades — a new migration (V_17_6_0.AddContentTypeIdIndexForContent) creates the same index. It uses the CreateIndex<ContentDto>() migration helper, so the index is generated from the exact same DTO definition — the migrated and freshly-installed schemas cannot drift. It is guarded by IndexExists (safe to re-run) and uses EnsureLongCommandTimeout since building the index can take a while on large tables.

Testing

Solution builds and CI checks should pass. The existing SchemaValidationTest verifies the DTO-derived schema is internally consistent, which now includes the new index.

On starting up Umbraco and running either an attended or an unattended migration, the index should be created:

image

Copilot AI review requested due to automatic review settings July 8, 2026 12:32
@claude

claude Bot commented Jul 8, 2026

Copy link
Copy Markdown

Claude finished @AndyButland's task in 2m 27s —— View job


PR Review

Target: origin/v17/dev · Based on commit: 1ed1c69c · Skipped: 0 files out of 3 total

Adds a non-clustered index on umbracoContent(contentTypeId) to allow seek-based lookups (instead of full table scans) on content-type-scoped operations — primarily the cmsContentNu rebuild path.


No breaking changes detected.


No issues found

The implementation is clean and correct:

  • Fresh installs[Index(IndexTypes.NonClustered, Name = "IX_umbracoContent_contentTypeId")] on ContentDto.ContentTypeId (line 32) ensures the schema creator builds the index from the same DTO definition as the migration.
  • UpgradesAddContentTypeIdIndexForContent.MigrateAsync() guards with IndexExists before calling CreateIndex<ContentDto>(IndexName), so the migration is safe to re-run and cannot drift from the DTO-derived schema.
  • Long-running installsEnsureLongCommandTimeout is applied before building the index, matching the same pattern used in sibling migrations (e.g. AddContentVersionDateIndex).
  • IndexName constant is constructed from the same ContentDto constants used in the [Index] attribute, making accidental name drift impossible.
  • Migration registration in UmbracoPlan.cs is positioned correctly after the final V_17_4_0 step.

Labels applied: area/backend, category/performance.


Approved

This looks good to be merged as-is, but please do a manual sanity check and testing before merging.

@claude claude Bot added area/backend category/performance Fixes for performance (generally cpu or memory) fixes labels Jul 8, 2026
@AndyButland AndyButland changed the title Performance: Add index on umbracoContent.contentTypeId Performance: Add index on umbracoContent.contentTypeId Jul 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a supporting database index on umbracoContent(contentTypeId) to improve performance for content-type-scoped queries (notably published cache rebuild operations triggered by content type structural changes).

Changes:

  • Add a DTO-declared non-clustered index on ContentDto.ContentTypeId so fresh installs create it automatically.
  • Add an upgrade migration (V_17_6_0.AddContentTypeIdIndexForContent) to create the same index on existing databases (guarded by IndexExists and using EnsureLongCommandTimeout).
  • Register the migration step in UmbracoPlan.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/Umbraco.Infrastructure/Persistence/Dtos/ContentDto.cs Declares the new umbracoContent(contentTypeId) index for schema creation on new installs.
src/Umbraco.Infrastructure/Migrations/Upgrade/V_17_6_0/AddContentTypeIdIndexForContent.cs Adds an upgrade migration to create the index on existing databases using the DTO-defined index definition.
src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs Wires the new migration into the upgrade plan for the 17.6.0 step.

@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

@Zeegaan Zeegaan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me 😁
Would love to know how much this improves things 🤔

@Zeegaan
Zeegaan merged commit 3de03fe into v17/dev Jul 12, 2026
33 of 34 checks passed
@Zeegaan
Zeegaan deleted the v17/improvement/add-index-for-content-content-type branch July 12, 2026 23:34
@AndyButland

Copy link
Copy Markdown
Contributor Author

This looks to be an index we clearly should have - it's a foreign key column, used in joins and queries like this one. But I have a request out to test on a large copied customer database that's showing performance issues with this step, so will hopefully have some numbers before merging this in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/backend category/performance Fixes for performance (generally cpu or memory) fixes release/17.6.0 release/18.1.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants