Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve change tracking performance #369

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Turnerj
Copy link
Member

@Turnerj Turnerj commented Oct 1, 2023

Fixes #362

When adding a very large number of entities to the change tracker, it was performing an extreme number of calls to GetValue on the PropertyInfo. This isn't typically slow but is very slow when call as often as it was.

This PR contains two primary changes to improve the performance of the existing code

  • Slight change in GetEntry lookups to avoid calling GetIdValue unnecessarily
  • Dynamically generate a delegate for the internal mechanism of GetIdValue

Up to 98% faster for setting the entity state.

Before

Method EntryCount Mean Error StdDev Allocated
SetEntityState 100 352.7 us 6.66 us 6.84 us 2 B
SetEntityState 1000 32,571.1 us 161.22 us 134.62 us 30 B
SetEntityState 10000 3,402,924.9 us 45,554.20 us 40,382.61 us 3656 B

After

Method EntryCount Mean Error StdDev Allocated
SetEntityState 100 22.62 us 0.450 us 0.645 us -
SetEntityState 1000 911.66 us 17.737 us 18.979 us 1 B
SetEntityState 10000 82,002.73 us 1,611.556 us 3,104.921 us 69 B

@Turnerj Turnerj added bug affects-writing Write-related issue labels Oct 1, 2023
@Turnerj
Copy link
Member Author

Turnerj commented Oct 1, 2023

There are further improvements possible based on the scenario in #362 as a big problem with the implementation when setting multiple entities is that the number of checks via GetEntry grows with every extra entity.

That is to say, you add 10 items to an empty entity container:

  • The first will check 0 items
  • The second will check 1 item
  • The third will check 2 items
  • etc

We can avoid a bunch of checks by not checking the items we're adding against themselves while we're adding them. So if someone were to add 500,000 items, we don't actually need to check them against each other.

That said, without doing the checks, it does mean it is possible for someone to intentionally double up the exact same reference entity in the database (eg. the enumerable has the same entity twice). This could be avoided by chucking the whole thing in a HashSet perhaps but that will cause a large amount of allocations, especially for the case with 500,000 entities being added.

@Turnerj
Copy link
Member Author

Turnerj commented Oct 1, 2023

I would like to work out a good/better solution for adding many entries at once without a large number of allocations while addressing the underlying performance problem before merging this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects-writing Write-related issue bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for multithreading
1 participant