1

I know the problem of the first EF query being slow has already been discussed, but none of the answers seemed to fit.

When I run an EF query for the first time, it takes 3 to 5 seconds to execute. When I run it a second time, it only takes milliseconds.

Test code :

Stopwatch sw = new Stopwatch();

Console.WriteLine("--- CONNECTION ---");
sw.Restart();
Context = new Connection();
sw.Stop();
Console.WriteLine("Elapsed time in seconds: " + sw.Elapsed.ToString(@"s\.ffff"));

Console.WriteLine("--- FIRST QUERY ---");
sw.Restart();
Context.Set<T>().Count();
sw.Stop();
Console.WriteLine("Elapsed time in seconds: " + sw.Elapsed.ToString(@"s\.ffff"));

Console.WriteLine("--- SECOND QUERY ---");
sw.Restart();
Context.Set<T>().Count();
sw.Stop();
Console.WriteLine("Elapsed time in seconds: " + sw.Elapsed.ToString(@"s\.ffff"));

Console output :

--- CONNECTION ---
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'D:\Developpement\CSharp_Prism\Test_Prism_2\Prism\src\Shell\bin\Debug\System.Data.SQLite.EF6.dll' chargé
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'D:\Developpement\CSharp_Prism\Test_Prism_2\Prism\src\Shell\bin\Debug\System.Data.SQLite.dll' chargé
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'D:\Developpement\CSharp_Prism\Test_Prism_2\Prism\src\Shell\bin\Debug\EntityFramework.SqlServer.dll' chargé
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_64\System.Transactions\v4.0_4.0.0.0__b77a5c561934e089\System.Transactions.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
Elapsed time in seconds: 0.2727

--- FIRST QUERY ---
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data.OracleClient\v4.0_4.0.0.0__b77a5c561934e089\System.Data.OracleClient.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
Native library pre-loader is trying to load native SQLite library "D:\Developpement\CSharp_Prism\Test_Prism_2\Prism\src\Shell\bin\Debug\x64\SQLite.Interop.dll"...
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.Entity\v4.0_4.0.0.0__b77a5c561934e089\System.Data.Entity.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.resources\v4.0_4.0.0.0_fr_b77a5c561934e089\System.Xml.resources.dll' chargé
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Dynamic\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Dynamic.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_64\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'C:\Windows\Microsoft.Net\assembly\GAC_64\System.EnterpriseServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.Wrapper.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'Shell.vshost.exe' (Managé (v4.0.30319)) : 'D:\Developpement\CSharp_Prism\Test_Prism_2\Prism\src\Shell\bin\Debug\fr\EntityFramework.resources.dll' chargé
Elapsed time in seconds: 3.3032

--- SECOND QUERY ---
Elapsed time in seconds: 0.0035

Yes, this is French, sorry. Basically, this is the "Skipped loading symbols" message.

The assemblies list changes depending on which query I use : Context.Set<T>() doesn't load anything and is extremely quick. Context.Set<T>().Count()and Context.Set<T>().ToList() are both pretty slow.

I'm not sure what these messages really mean (if loading is skipped why does it still take time?), but if I have to load some assemblies, I'd rather do it at startup.

Is that possible? Or is there a way to speed things up?

Thanks.

Raya
  • 101
  • 1
  • 7

1 Answers1

2

Context.Set<T>() does not load anything, because this is a query definition, not query execution. Both Count() and ToList() methods force query execution (i.e. query will be converted to SQL an executed on database).

First query always will be executed more slowly, because EF needs to load metadata (it uses either xml or code mappings for that).

Suggested reading: Performance Considerations (Entity Framework)

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • Isn't there a way to make EF load metadata at startup? – Raya May 10 '14 at 09:52
  • 1
    @Raya: You can somewhere in your startup routine call the code: `using (var ctx = new MyContext()) { ctx.Database.Initialize(false); }` That only loads the metadata (and runs the DB initializer if you have one). – Slauma May 10 '14 at 11:41
  • @Slauna: I tried your solution but it doesn't seem to load anything, metadata are still loaded during the first query. – Raya May 11 '14 at 08:09
  • @Raya before I saw `Slauma`'s comment, I had already came to that same conclusion. I added the exact same code to my app bootstrapper and started using a splash screen. It does (at least for me) load all the necessary bloat for EF and then my first query in the app is lightning fast. – vane May 01 '15 at 21:39