web-dev-qa-db-fra.com

Entity Framework très lent à charger pour la première fois après chaque compilation

Comme le titre le suggère, la première requête pose un problème avec une base de données SQL Server utilisant Entity Framework. J'ai essayé de chercher une réponse, mais personne ne semble avoir de solution à ce problème.

Les tests ont été réalisés dans Visual Studio 2012 à l'aide d'Entity Framework 6. J'ai également utilisé le modèle de vues T4 pour précompiler les vues. La base de données était sur un SQL Server 2008. Nous avons environ 400 POCO (400 fichiers de mappage), nous n'avons que 100 lignes de données dans la table de base de données.

La capture suivante est mon code de test et mon résultat.

static void Main(string[] args){
    Stopwatch st=new Stopwatch();
    st.Start();
    new TestDbContext().Set<Table1>.FirstOrDefault();
    st.stop();
    Console.WriteLine("First Time "+st.ElapsedMilliseconds+ " milliseconds");

    st.Reset();
    st.Start();
    new TestDbContext().Set<Table1>.FirstOrDefault();
    st.stop();
    Console.WriteLine("Second Time "+st.ElapsedMilliseconds+ " milliseconds");
}

Résultats de test

First Time 15480 milliseconds
Second Time 10 milliseconds
39
LeoLi

Sur la première requête, EF compile le modèle. Cela peut prendre un certain temps pour un modèle de cette taille. 

Voici 3 suggestions: http://www.fusonic.net/fr/blog/2014/07/09/three-steps-for-fast-entityframework-6.1-first-query-performance/

Un résumé:

  1. Utilisation d'un magasin de modèles de base de données mis en cache
  2. Générer des vues pré-compilées
  3. Génère une version pré-compilée de entityframework en utilisant n-gen pour éviter le jitting 

Je voudrais également m'assurer que je compile l'application en mode publication lorsque je fais les tests.

Une autre solution consiste à scinder le DBContext. 400 entités, c'est beaucoup et il devrait être plus agréable de travailler avec de plus petits morceaux. Je ne l'ai pas essayée mais je suppose qu'il serait possible de construire les modèles un par un, ce qui signifie qu'aucune charge ne prend 15 secondes. Voir le message de Julie Lerman https://msdn.Microsoft.com/en-us/magazine/jj883952.aspx

34
Mikael Eliasson

Avec EF Core, vous pouvez tricher et charger le modèle tôt après avoir appelé services.AddDbContext (vous pouvez probablement faire quelque chose de similaire avec EF6 aussi, mais je ne l’ai pas testé).

services.AddDbContext<MyDbContext>(options => ...);
var options = services.BuildServiceProvider()
                      .GetRequiredService<DbContextOptions<MyDbContext>>();
Task.Run(() =>
{
    using(var dbContext = new MyDbContext(options))
    {
        var model = dbContext.Model; //force the model creation
    }
});

Cela créera le modèle de dbcontext dans un autre thread pendant que le reste de l'initialisation de l'application est terminé (et peut-être d'autres échauffements) et le début d'une demande. De cette façon, il sera prêt plus tôt. Lorsque vous en aurez besoin, EFCore attendra que le modèle soit créé s'il n'est pas encore terminé. La Model est partagée entre toutes les instances de DbContext. Vous pouvez donc déclencher et oublier ce dbcontext factice.

1
Yepeekai

Vous pouvez essayer quelque chose comme ça: (ça a marché pour moi)

protected void Application_Start()
{

    Start(() =>
    {
        using (EF.DMEntities context = new EF.DMEntities())
        {
            context.DMUsers.FirstOrDefault();
        }
    });
}
private void Start(Action a)
{
    a.BeginInvoke(null, null);
} 

Entity Framework - Première requête lente

1
AllmanTool

Si vous avez beaucoup de tables qui ne sont pas utilisées sur c #, excluez-les. 

Ajouter une classe partielle, ajouter le code suivant et référencer cette fonction sur OnModelCreating 

void ExcludedTables(DbModelBuilder modelBuilder)
{
    modelBuilder.Ignore<Table1>();
    modelBuilder.Ignore<Table>();
   // And so on
}
0
roncansan

ça marche pour moi:

using (MyEntities db = new MyEntities())                
{
   db.Configuration.AutoDetectChangesEnabled = false; // <----- trick
   db.Configuration.LazyLoadingEnabled = false; // <----- trick

   DateTime Created = DateTime.Now;

   var obj = from tbl in db.MyTable
      where DateTime.Compare(tbl.Created, Created) == 0
      select tbl;

   dataGrid1.ItemsSource = obj.ToList();
   dataGrid.Items.Refresh();
}
0
user3047352