Augmenter les performances sur les requêtes avec beaucoup de mappages un à plusieurs

dapper entity-framework petapoco sql-server

Question

J'utilise Entity Framework pour SQL Azure et dans une page de mon application, nous affichons un certain nombre de données liées à l'utilisateur. Nous chargeons un maximum de 30 éléments sur la page, mais chaque élément comporte 5 mappages un à plusieurs à d'autres objets. Le temps de requête est raisonnable mais je perds pas mal de performances sur le mappage d'objets. (presque une seconde entière).

Voici un exemple de ce à quoi ressemble mon objet

public class Task
{
    public string Name {get; set;}
    public string Status {get; set;}
    public DateTime DueDate {get; set;}
    public IEnumerable<TaskData> Data {get; set;}
    public IEnumerable<Transaction> Transactions {get; set;}
    public IEnumerable<File> Files {get; set;}
    public IEnumerable<Comment> Comments {get; set;}
    public IEnumerable<People> People {get; set;}
}

Une tâche a un nom, un statut et une date d'échéance. Il a également beaucoup de TaskData qui sont des paires nom / valeur personnalisées, de nombreuses transactions qui affichent un historique de la tâche, de nombreux fichiers, de nombreux commentaires et de nombreuses personnes qui y travaillent.

Ma requête EF ressemble à ceci.

var Items = context.Items.Include(x=>x.Data).Include(x=>x.Files).Include(x=>x.Comments).Include(x=>x.People).Where(some constraint).ToList();

La pertinence d'une tâche spécifique dépend d'abord du statut, puis de la date d'échéance. J'ai donc créé un remplacement IComparable à utiliser avec le tri. Le fait est que les requêtes paginées ne fonctionnent pas bien dans ce scénario car le tri n'est pas basé sur un int ou une date (est-ce que je suis correct?)

Dans le reste de notre application, nous affichons moins d'informations sur chaque tâche et Linq2Entities fonctionne correctement. Le mappage d'objet dans ce cas nous tue cependant. Je suis allé directement sur la base de données avec Dapper, mais les mappages un-à-plusieurs ont leurs inconvénients. Pour quelques relations, je pense que cela fonctionnerait bien mais pas pour 5-6. Ma prochaine chose à regarder était PetaPoco, mais je n’ai pas été très loin avant de penser que je ferais mieux de poser la question ici en premier.

Suis-je fou d'essayer de ramener autant de données? Quelles sont mes options pour obtenir un maximum de performance? Je vais prendre un peu de complexité puisque ce n'est qu'un domaine de l'application.

Réponse acceptée

Je suis prêt à parier que votre requête EF récupère trop de données. La technique de récupération «optimale» dépend fortement du type et de la quantité de données à extraire.

Cette connaissance vous permet d’ajuster les requêtes que vous exécutez en fonction de votre ensemble de données attendu.

Par exemple, si vous ne tirez qu'un nombre limité d'entités avec beaucoup de sous-entités, le modèle que j'ai écrit ici fonctionne bien:

Comment mapper des listes d'objets imbriqués avec Dapper

Si vous connaissez les identifiants que vous extrayez et qu'il y en a moins de 2000, vous pouvez tout raccourcir en interrogeant une seule grille et en utilisant QueryMultiple par exemple:

cnn.QueryMultiple(@"select * from Tasks where Id in @ids 
select * from Files where TaskId in @ids
.. etc ..", new {ids = new int[] {1,2,3}});

Si vous tirez un jeu plus volumineux, vous devrez peut-être procéder par lots ou par étapes.


Pour votre exemple particulier, j'interrogerais les Tasks pour obtenir tous les identifiants et les données de la tâche, puis mapper les relations en utilisant un seul QueryMultiple à toutes les tables associées.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi