Skip to content

Optimize BuildReseedSql for SqlServerDbAdapter #159

@SteffenHaugeEG

Description

@SteffenHaugeEG

Benchmarking our current integration tests it became clear that our test setup time took longer than the actual test case execution.
And looking further into this, the option WithReseed = true is the culprit.

The Reseed SQL uses on average 870ms (per test execution!) on my machine.
Tweaking the SQL has brought this time down to average 160ms, a 700ms reduction (again per test case).
With a few thousand tests this makes a huge difference in total runtime :)

The tweaked SQL:

DECLARE @SchemaAndTableName sysname = N''
DECLARE @NewSeedValue int = 0

-- find all non-system tables and load into a cursor
DECLARE IdentityTables CURSOR FAST_FORWARD
FOR
    SELECT  QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id, db_id())) + '.' + QUOTENAME(t.name) as schemaAndTableName,
            IDENT_SEED(QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id, db_id())) + '.' + QUOTENAME(t.name)) - 1 as newSeedValue
     FROM sys.tables t
        JOIN sys.columns c ON t.object_id=c.object_id
        JOIN sys.identity_columns ic on ic.object_id = c.object_id
    WHERE c.is_identity = 1
    AND ic.last_value IS NOT null -- Skip null values
    AND ic.last_value <> IDENT_SEED(QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id, db_id())) + '.' + QUOTENAME(t.name)) - 1 -- Skip if we don't need to reseed the value
    AND OBJECT_SCHEMA_NAME(t.object_id, db_id()) + '.' + t.name in ('{string.Join("', '", tablesToDelete)}')
OPEN IdentityTables
FETCH NEXT FROM IdentityTables INTO @SchemaAndTableName, @NewSeedValue
WHILE @@FETCH_STATUS = 0
    BEGIN
     -- reseed the identity only on tables that actually have had a value, otherwise next value will be off-by-one
     -- https://stackoverflow.com/questions/472578/dbcc-checkident-sets-identity-to-0
        DBCC CHECKIDENT(@SchemaAndTableName, RESEED, @NewSeedValue)
        FETCH NEXT FROM IdentityTables INTO  @SchemaAndTableName, @NewSeedValue
    END
 DEALLOCATE IdentityTables

Tweaks:
Instead of selecting the schema and table separately, this can be done in a single select.
We can select identityInitialSeedValue - 1 directly as this is the value passed to DBCC CHECKIDENT anyways.
We can filter out cases where ic.last_value is null in the where clause.
We can check the current seed value and make sure it's different from identityInitialSeedValue - 1, since otherwise we just set it to it's current value anyways.
Lastly instead of creating the DBCC CHECKIDENT command as a string and executing it, we can just call the function directly using the 2 new variables which contain what we need directly.

Let me know if I missed something :)
I would be happy to create a PR for this as well, just let me know.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions