2009-09-21 4 views
1

J'utilise ASP.NET MVC et Azure Table Storage dans la structure de développement local. Mon code est très lent pagination lorsque l'on travaille avec un grand ResultSet:Comment puis-je accélérer mon code de pagination dans ASP.NET MVC avec Azure?

var PageSize = 25; 
var qResult2 = from c in svc.CreateQuery<SampleEntity>(sampleTableName) 
          where c.PartitionKey == "samplestring" 
          select c; 
TableStorageDataServiceQuery<SampleEntity> tableStorageQuery = 
       new TableStorageDataServiceQuery<SampleEntity> 
       (qResult2 as DataServiceQuery<SampleEntity>); 
var result = tableStorageQuery.ExecuteAllWithRetries() 
           .Skip((page - 1) * PageSize) 
           .Take(PageSize); 
var numberOfEntities = tableStorageQuery.ExecuteAllWithRetries().Count 
ViewData["TotalPages"] = (int)Math.Ceiling((double) numberOfEntities/PageSize); 
ViewData["CurrentPage"] = page; 
return View(result); 

Le ViewData est utilisé par la vue de calculer les liens de pagination en utilisant le code du livre MVC Sanderson. Pour une table Azure avec plus de 1000 entités, c'est très lent. Pour commencer, "Count" prend beaucoup de temps pour calculer le nombre total d'entités. Si je lis correctement mon livre LINQ, c'est parce que la requête n'implémente pas ICollection. Le livre est "Pro LINQ" de Joseph Rattz.

Même si je règle "numberOfEntities" sur le total connu (par exemple 1500), la pagination est toujours lente pour les pages supérieures à 10. Je suppose que .Skip et/ou .Take sont lents. En outre, j'appelle deux fois ExecuteAllWithRetries(), et cela ne peut pas aider si en fait Azure est interrogé deux fois.

Quelle stratégie dois-je suivre pour effectuer une pagination sur de grands ensembles de données avec ASP.NET MVC et Azure?

EDIT: Je n'ai pas besoin de connaître le nombre total exact de pages.

Répondre

4

Skip et Take ne sont pas le problème ici - ils seront exécutés contre le IEnumerable, qui sera déjà en mémoire et donc très rapide.

ExecuteAllWithRetriesExecuteAllWithRetries est probablement le coupable ici - vous récupérez essentiellement toutes les entités de la partition à partir du stockage distant dans cet appel, ce qui se traduira par une très grande charge utile.

La pagination de la manière que vous montrez est assez difficile dans le stockage de table. Voici quelques questions:

  • Le seul ordre qui est garanti est le PartitionKey/RowKey commande, vous devez concevoir votre RowKeys avec cela à l'esprit.

  • Vous pouvez effectuer le Take dans la requête (c.-à-d. Votre qResult2), ce qui réduit le nombre d'entités qui transitent par le réseau.

  • Pour exécuter la fonctionnalité Skip, vous devez utiliser un opérateur de comparaison. Ainsi, vous aurez besoin de savoir où vous êtes dans le jeu de résultats et d'interroger tous les RowKeys ci-dessus de cette valeur (c.-à ajouter quelque chose comme where c.RowKey > [lastRowKey] à votre requête)

  • Il n'y a pas moyen de récupérer un nombre sans garder une trace de vous-même (ou récupérer la table entière comme vous le faites déjà). Selon votre conception, vous pouvez stocker le nombre avec chaque entité (c.-à-d. Utiliser une valeur incrémentée) - mais assurez-vous de garder la trace des conflits d'édition simultanés, etc. Si vous gardez la trace du nombre avec chaque entité, alors vous pouvez également effectuer votre Skip en utilisant cela aussi. Une autre option consisterait à stocker le compte dans une seule valeur dans une autre entité (vous pouvez utiliser la même table pour assurer un comportement transactionnel). Vous pouvez aussi combiner ces approches (stocker le compte dans une seule entité, obtenir la concurrence optimiste, et également la stocker dans chaque entité pour savoir où elle se trouve).

  • Une alternative serait, si possible, de se débarrasser complètement du compte. Vous remarquerez que quelques grands sites évolutifs font cela - ils ne fournissent pas une liste exacte du nombre de pages disponibles, mais ils peuvent vous laisser aller quelques pages en avant/en arrière.Cela élimine fondamentalement le besoin de compter - vous avez juste besoin de garder une trace du RowKeys pour les pages suivantes/précédentes.

+0

Merci pour vos commentaires. Tu m'as convaincu que j'allais dans la mauvaise direction. J'ai maintenant implémenté la pagination comme indiqué sur http://blog.smarx.com/posts/paging-over-data-in-windows-azure-tables et j'en suis assez content. Pour mon application, je n'ai pas besoin d'afficher le nombre total de pages, donc je me suis débarrassé de "count" comme vous l'avez suggéré. Traiter les jetons de continuation était plus facile que je ne le pensais, et ils s'occupaient facilement de la fonctionnalité «sauter» et «prendre» que j'avais auparavant. Merci encore. – royco