Skip to content

perf(sqlserver): optimize stream lookups and append writes - #621

Open
nmummau wants to merge 3 commits into
Eventuous:devfrom
nmummau:fix/617
Open

nmummau wants to merge 3 commits into
Eventuous:devfrom
nmummau:fix/617

Conversation

@nmummau

@nmummau nmummau commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Reduce SQL Server index maintenance and intermediate writes on appends, and cover stream-name lookups without changing the event store API.

Upgrade notes

These are non-breaking optimizations. Existing databases remain compatible without applying them.

With InitializeDatabase = true, startup applies the index changes and updates append_events through the existing transactional schema initializer. Repeated initialization is safe.

With initialization disabled (the default), consumers must apply the changes through their database deployment process to receive the optimizations:

  1. Replace the Streams.UQ_StreamName unique constraint with a unique nonclustered index on StreamName including Version. Keep the name UQ_StreamName, and perform the replacement in a transaction.
  2. Drop Messages.IDX_EventsStream if it exists.
  3. Deploy the updated append_events procedure from Scripts/2_AppendEvents.sql.

Use the configured schema name when applying the SQL scripts. Alternatively, explicitly run Schema.CreateSchema(...) from the upgraded package.

Validation

  • All 46 SQL Server store integration tests passed on SQL Server 2022 with .NET 10, including the existing append concurrency tests.
  • Schema regression tests cover fresh schemas, upgrades, repeated initialization, uniqueness, and data preservation.
  • Append-position tests cover empty, single-event, and multi-event batches on new and existing streams, including reuse of a connection after earlier appends.
  • No throughput benchmark or execution-plan comparison was performed.

Fixes #617
Fixes #618
Fixes #619

Replace the UQ_StreamName constraint with a unique index that includes
Version, avoiding key lookups during appends and stream reads.

Upgrade existing schemas during initialization and add regression tests
for the upgrade, repeated initialization, and preserved data and uniqueness.

Release note: This is a non-breaking schema optimization. Applications
using InitializeDatabase=true receive the index upgrade on startup.
Applications managing their schema separately must replace the
UQ_StreamName constraint with a unique nonclustered index on StreamName
that includes Version, retaining the UQ_StreamName name. Existing schemas
remain compatible but do not receive the optimization until upgraded.

Fixes Eventuous#617
Remove IDX_EventsStream, since UQ_StreamIdAndStreamPosition already
supports filtering by StreamId. Drop the index during schema
initialization for existing databases.

Add regression tests for fresh schemas, upgrades, repeated
initialization, and event payload preservation.

Applications without InitializeDatabase enabled can apply:
DROP INDEX IF EXISTS IDX_EventsStream ON eventuous.Messages;
Replace eventuous with the configured schema name.

Existing schemas remain compatible without this optimization.

Fixes Eventuous#618
Use SCOPE_IDENTITY() to capture the last inserted GlobalPosition,
removing the table variable, OUTPUT INTO, and MAX query.

Add regression tests for empty, single-event, and multi-event batches
on new and existing streams, including reused connections.

Applications with InitializeDatabase disabled must deploy the updated
append_events procedure to receive this optimization.

Validated with all 46 SQL Server store tests, including concurrency tests.

Fixes Eventuous#619
@github-actions

Copy link
Copy Markdown

Test Results

   48 files  ±0     48 suites  ±0   15m 3s ⏱️ -36s
  624 tests +7    624 ✅ +7  0 💤 ±0  0 ❌ ±0 
1 241 runs  +7  1 241 ✅ +7  0 💤 ±0  0 ❌ ±0 

Results for commit 0a8916f. ± Comparison against base commit 60a7643.

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

Labels

None yet

Projects

None yet

1 participant