2017-02-22 1 views
0

Voici mon modèle:EntityFramework - charge que le dernier enfant de la collection (problème de performance)

public partial class auctions 
{ 
    public int id { get; set; } 
    public virtual ICollection<auction_data> auction_data { get; set; } 
} 
public partial class auction_data 
{ 
    public int id { get; set; } 
    public int auction_id { get; set; } 
    public string title { get; set; } 
    public virtual auctions auctions { get; set; } 
} 

Chaque vente aux enchères peut avoir des milliers od éléments auction_data qui s'y rattachent. Mais je suis intrested que dans le dernier de celui-ci:

var matchingAuctions = context.auctions.Where(a => /** some conditions **/); 
foreach (auctions auction in matchingAuctions) 
{ 
    var data = auction.auction_data.LastOrDefault(); // <---- takes very long time and memory when having large count of auction_data 
} 

Il semble que des charges EF tous auction_data dans la mémoire, puis retourne le dernier. La question est: comment puis-je améliorer les performances de ce code et éviter de charger tous ces enregistrements en mémoire?

EDIT: une synchronisation

DateTime t1 = DateTime.Now; 
var data = auction.auction_data.LastOrDefault(); 
DateTime t2 = DateTime.Now; 
TimeSpan diff = t2 - t1; // 8.8s 


DateTime t1 = DateTime.Now; 
var data = auction.auction_data.OrderByDescending(a => a.id).FirstOrDefault(); 
DateTime t2 = DateTime.Now; 
TimeSpan diff = t2 - t1; // 8.7s 

DateTime t1 = DateTime.Now; 
var data = auction.auction_data.Last(); 
DateTime t2 = DateTime.Now; 
TimeSpan diff = t2 - t1; // 8.7s 

int id = auction.id; 
DateTime t1 = DateTime.Now; 
var data = context.auction_data.Where(d => d.auction_id == id).OrderByDescending(d => d.id).FirstOrDefault(); 
DateTime t2 = DateTime.Now; 
TimeSpan diff = t2 - t1; // 0.06s 
+0

Vous pouvez inverser le tri, puis prendre la 'd'abord()' 'au lieu du dernier()' –

+0

Pourquoi prendriez-vous la dernière rangée quand aucune commande n'est appliquée? _Définir ... dernier? (plus haut Id/dernier datetime?) _ –

+0

Également essayé de cette façon, mais a obtenu le même résultat – user3175253

Répondre

2

Il est normal. Lorsque vous écrivez auction.auction_data, il lit toutes les enchères.auction_data. Si j'étais vous je ferais cela à de meilleures performances:

public partial class auctions 
{ 
    public int id { get; set; } 
    public int lastDataId { get; set;} 
    public virtual ICollection<auction_data> auction_data { get; set; } 
} 

et lors de l'insertion de données insérer l'id comme le dernier.

Comme un test: Je n'ai pas une grande base de données pour tester, mais peut-être le changeing Last() au lieu de LastOrDefault() peut halp vous. Je lis ceci:

LastOrDefault est une méthode utile. Il trouve le dernier élément dans une collection qui correspond à une condition

afin de tester Maching à conditionner besoin de lire tous les enregistrements, mais peut-être dernier() ne

+0

S'il vous plaît jeter un oeil sur ma question (édité) – user3175253

+0

Je ne croyais pas en 'OrderByDescending' de la première. C'est presque la même chose. Mais le dernier (bon) moyen est ce que j'ai suggéré, vous devez avoir un identifiant de données. ? –

+0

Une autre chose: 'var data = contexte.auction_data.Where (d => d.auction_id == id) .OrderByDescendant (d => d.id) .FirstOrDefault();' n'a pas besoin de ** Tri ** est seulement un élément quand id est la clé primaire –

0

Change:

var data = auction.auction_data.LastOrDefault(); 

à:

var data = auction.auction_data.OrderByDescending(x => x.id).FirstOrDefault(); 
+1

J'ai essayé de cette façon, mais cela ne fait presque aucune différence (dans mon test 8,8 secondes vs 8,7 secondes) – user3175253

+0

Avez-vous des indexes en place? Je me demande, car EF fonctionne assez bien lorsque vos tables de base de données sont indexées correctement. – Stuart

+1

oui, j'ai clé primaire sur ID.Comme je l'ai mentionné, le problème est EF lit toute la table en mémoire, puis retourne l'enregistrement au lieu de lire une seule ligne de la table – user3175253