-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Create lazy-loading and change-tracking proxy types lazily #20135
Comments
@henrikdahl8240 Can you attach your EF model (entity types and DbContext) so that we can investigate. This seems slower than expected even for 4000 entity types. |
Can't you give a suggestion for how to do that without challenging the immaterial rights. Do you for example have a reference for a Roslyn project which anonymizes all names in all projects in a solution? I would like to share the model, but I would like to do it without disclosing anything for real. |
@henrikdahl8240 You can run an obfuscator? |
Yes, but I have never done that before. Can you suggest how to do that? Can I see the result myself? Is there one built-in in Visual Studio? |
https://docs.microsoft.com/en-us/visualstudio/ide/dotfuscator/?view=vs-2019 Then you can decompile the resulting dll and extract the relevant classes |
Thank you very much, Erik. Do you also have a suggestion concerning the decompilation step? |
@henrikdahl8240 If you don't want to share it publicly, then you can send it to me directly and we will keep it private. avickers at microsoft.com |
@ajcvickers It sounds excellent. I will put some efforts into that. |
I usually use dotPeek |
OK. I will take a look. Thank you for the hints, @ErikEJ |
@ajcvickers As you may see, I mailed you a soution on March 6. 2020 13:46. Perhaps you may run it to reproduce the problems yourself? The mail details the few steps you should go through. |
@henrikdahl8240 Thanks--we got the code. Note for team: I am able to reproduce this; culprit is model building but I haven't profiled to find out where. /cc @AndriySvyryd Running the code below on my fast machine without lazy-loading proxies:
With proxies:
Model has 5,860 entity types with a total of 13,876 navigations. EntityTypeConfigurations are already being used. using (HenrikDahl_DbContext dbContext = new HenrikDahl_DbContext(new DbContextOptionsBuilder<HenrikDahl_DbCon
.UseLazyLoadingProxies()
.UseSqlServer(Your.SqlServerConnectionString, opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).T
{
Console.WriteLine("Creating model...");
var timer = Stopwatch.StartNew();
var model = dbContext.Model;
timer.Stop();
Console.WriteLine($"Done in {timer.ElapsedMilliseconds}");
Console.WriteLine("Creating database...");
timer = Stopwatch.StartNew();
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
timer.Stop();
Console.WriteLine($"Done in {timer.ElapsedMilliseconds}");
Console.WriteLine("Running query...");
timer = Stopwatch.StartNew();
var samoyed = dbContext.Samoyeds.FirstOrDefault();
timer.Stop();
Console.WriteLine($"Done in {timer.ElapsedMilliseconds}");
} |
It might be just the time it takes to create the proxy types |
Shouldn't proxy types generally be created as they are needed and not up-frot, i.e. created lazy-wise? Perhaps it could be an option for UseLazyLoadingProxies whether the proxy classes should be created eager-wise or lazy-wise. Otherwise I guess it will always be a pain in situations with relatively many entity types. I assume that the requirement of using "virtual" for all collections and navigation properties enable this. I would imagine, that EF Core should rather shine with many entity types than with few entity types. Probably many can figure out to make such ORM stuff if it only needs to perform well in situations with few entity types. I assume that all non-trivial enterprise solutions will have many, many entity types and it's here EF Core should shine, at least from my point of view. |
@AndriySvyryd Yes, but I think it would be good to understand where the time is being used even in the non-proxy model building. |
Notes from team triage:
This number of entity types and relationships is at the high end of what we see. We have a long-term goal to pre-compile the model, which is ultimately the way to make this the most performant. That being said, the perf here is a lot slower than I expected, which is why we're investigating. |
@henrikdahl8240 Many modern enterprise solutions are based on micro services and a limited number of entity types managed by each micro service. |
@ErikEJ How do you ensure domain level consistency in the situation you have on mind as you do not have the entire domain model in one database? |
@AndriySvyryd, @ajcvickers |
@DeluxeAgency2020 We'll investigate this in 5.0 timeframe, but it's unlikely that any significant improvement will be made for 5.0 RTM |
Tested on 6.0.0-preview.7 without proxies:
|
Related to the last point: #24902 |
From #20135 (comment)
|
Part of #626 Part of #15911 Fixes #20135 Fixes #14554 Fixes #24902 This is the lowest level of materialization interception--it allows the actual constructor/factory binding to be changed, such that the expression tree for the compiled delegate is altered. Introduces singleton interceptors, which cannot be changed per context instance without re-building the internal service provider. (Note that we throw by default if this is abused and results in many service providers being created.) The use of this for proxies has two big advantages: - Proxy types are created lazily, which vastly improves model building time for big models with proxies. See #20135. - Proxies can now be used with the compiled model, since the proxy types are not compiled into the model. See
Fixed in #28127. Perf for model with 449 entity types, 6390 properties, and 720 relationships. 6.0No proxies
Change tracking proxies
7.0No proxies
Change tracking proxies
Change tracking proxies and compiled model
See #24902. Also, see #28129. |
Very nice! |
Part of #626 Part of #15911 Fixes #20135 Fixes #14554 Fixes #24902 This is the lowest level of materialization interception--it allows the actual constructor/factory binding to be changed, such that the expression tree for the compiled delegate is altered. Introduces singleton interceptors, which cannot be changed per context instance without re-building the internal service provider. (Note that we throw by default if this is abused and results in many service providers being created.) The use of this for proxies has two big advantages: - Proxy types are created lazily, which vastly improves model building time for big models with proxies. See #20135. - Proxies can now be used with the compiled model, since the proxy types are not compiled into the model. See
I have made this simple function:
On my machine, it takes 4:18 to execute, i.e. four minutes and 18 seconds.
It is important to notice, that I have commented out the invocation of .UseLazyLoadingProxies(). I obviously need these proxies, so it's just to compare.
So now I uncomment .UseLazyLoadingProxies() so it will also be run, i.e.:
Now it takes 34:42 to execute, i.e. 34 minutes and 42 seconds. By simple subtraction, the invocation of .UseLazyLoadingProxies() adds approximately half an hour to the duration or makes initialization to take approximately 10 times longer time.
There was a lot of criticism on the initialization time in scope of EF 6. It seems like this gives exactly the same problem.
Can't you for instance lazy initialize or we could call it initialize on demand instead? Perhaps you have a better idea?
Do you agree, that it's a major problem, that use of your proxy feature forces initialization to take really long time?
I would like to mention, that I have in the magnitude of 4.000 entities in my model. Only one of these is being looked up by my small program example.
EF Core version: 3.1.2
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: NET Core 3.1
Operating system: Windows 10 Professional
IDE: Visual Studio 2019 16.4.5.
The text was updated successfully, but these errors were encountered: