Use CREATE INDEX with DROP_EXISTING=ON for index facet changes (SQL Server)#38271
Open
m-x-shokhzod wants to merge 1 commit into
Open
Use CREATE INDEX with DROP_EXISTING=ON for index facet changes (SQL Server)#38271m-x-shokhzod wants to merge 1 commit into
m-x-shokhzod wants to merge 1 commit into
Conversation
…erver) When an index facet changes (fill factor, sort order, uniqueness, filter, columns), the migration model differ produces a DropIndexOperation + CreateIndexOperation pair. On SQL Server this can be collapsed into a single `CREATE INDEX ... WITH (DROP_EXISTING = ON)`, which: - Lets queries continue using the old index while the new one is being built (no un-indexed gap during a long rebuild on large tables) - Atomically replaces the old index in a single statement The rewrite lives in SqlServerMigrationsSqlGenerator.RewriteOperations (new helper RewriteDropAndCreateIndexAsDropExisting). The matching DropIndexOperation is removed from the operation list and the CreateIndexOperation is marked with a new internal annotation SqlServerAnnotationNames.UseDropExisting, which IndexOptions reads to emit DROP_EXISTING = ON in the WITH clause. Limited to standard indexes — memory-optimized, full-text, and vector indexes use different syntax/restrictions and fall back to the existing drop+create path. MigrationsModelDiffer is unchanged; the differ still emits Drop+Create as before. Other providers are unaffected. Fixes dotnet#35067
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When an index facet changes (fill factor, sort order, uniqueness, filter, columns),
MigrationsModelDifferproduces aDropIndexOperation+CreateIndexOperationpair, which the SQL Server generator emits as two statements:This is suboptimal: during the drop, queries can't use the index → potentially full table scans, and on large tables the gap can be significant.
SQL Server supports
CREATE INDEX ... WITH (DROP_EXISTING = ON)since SQL Server 2008, which:After
Implementation
The rewrite lives entirely in the SQL Server provider:
SqlServerAnnotationNames.UseDropExistingSqlServerMigrationsSqlGenerator.RewriteDropAndCreateIndexAsDropExisting(called fromRewriteOperations, alongside the existingFixLegacyTemporalAnnotations) — detectsDrop+Createpairs for the same(Name, Table, Schema), removes the drop from the operation list, and marks the create withUseDropExisting = trueIndexOptionsreads the annotation and addsDROP_EXISTING = ONto theWITH (...)clause alongsideFILLFACTOR,ONLINE,SORT_IN_TEMPDB,DATA_COMPRESSIONLimited to standard indexes — memory-optimized, full-text, and vector indexes use different syntax/restrictions and fall back to the existing drop+create path.
MigrationsModelDifferis unchanged; the differ still emits Drop+Create as before. Other providers (MySQL, PostgreSQL, SQLite, Cosmos) are unaffected.Tests
Alter_index_make_uniqueAlter_index_change_sort_orderAlter_index_fill_factor_uses_drop_existingFILLFACTORchange collapses toWITH (FILLFACTOR = 90, DROP_EXISTING = ON)Alter_index_filter_uses_drop_existingWITH (DROP_EXISTING = ON), filter rendered afterWHEREAll 4 tests pass end-to-end against a real SQL Server instance (verified locally against Azure SQL Edge on Apple Silicon ARM64; the CI matrix will additionally verify against SqlServer 2019/2022/2025).
Full regression sweep:
EFCore.SqlServer.Tests1335/1335,SqlServerMigrationsSqlGeneratorTest124/124,MigrationsSqlServerTestindex tests 34/34.Fixes #35067