Partager via


Écriture d’un code efficace dans SharePoint Server

Dernière modification : lundi 30 novembre 2009

S’applique à : SharePoint Server 2010

Si vous écrivez des solutions personnalisées à l’aide du modèle objet SharePoint, soyez conscient des problèmes courants liés aux performances, à l’extensibilité et à l’évolutivité. Cette rubrique peut vous aider à résoudre efficacement les problèmes et à améliorer les performances des applications SharePoint existantes ou à écrire de nouvelles applications SharePoint. Dans les deux cas, vous devez comprendre comment faire en sorte que le modèle objet SharePoint travaille efficacement et comment appliquer des techniques de programmation générales spécifiquement à la plateforme SharePoint.

Utilisation d’objets SPQuery

Des requêtes bien conçues peuvent vous aider à éviter les problèmes de performance qui peuvent se produire au fil de l’augmentation de la taille des listes et des dossiers de votre site. Les techniques suivantes peuvent vous aider à utiliser des objets SPQuery de la manière la plus efficace possible.

  • Utilisez un objet SPQuery limité.

    Un objet SPQuery sans valeur pour RowLimit s’exécutera de façon peu performante et échouera sur des listes importantes. Spécifiez pour RowLimit un nombre compris entre 1 et 2 000 et si nécessaire, parcourez les pages de la liste. Pour un exemple de code qui montre comment procéder, voir Gestion de dossiers et de listes volumineux.

  • Limitez le jeu de résultats.

    Si votre requête renvoie plus d’éléments que le seuil configuré pour la requête dans Microsoft SharePoint Foundation 2010, la requête sera bloquée et vous ne recevrez pas de résultats. Le seuil de requête par défaut est de 5 000 éléments, mais vous pouvez le définir à une valeur inférieure. Pour les requêtes Microsoft SharePoint Server 2010, utilisez ContentIterator.MaxItemsPerQuery et parcourez les pages des résultats si vous avez besoin de tous les éléments.

  • Utilisez des champs indexés.

    Si vous faites une recherche sur un champ qui n’est pas indexé et que l’analyse qui en résulte rencontre plus d’éléments dans la liste que le seuil de requête, la requête sera bloquée. Définissez SPQuery.RowLimit à une valeur inférieure au seuil de la requête. La valeur de ContentIterator.MaxItemsPerQuery est nécessairement inférieure ou égale au seuil, qui est la valeur recommandée pour SharePoint Server 2010.

  • Assurez-vous d’inclure une des trois clauses OrderBy - ContentIterator.ItemEnumerationOrderByID, ContentIterator.ItemEnumerationOrderByPath ou ContentIterator.ItemEnumerationOrderByNVPField, qui permet l’utilisation de l’index.

    Sans une clause OrderBy, votre requête pourrait être bloquée. SharePoint Server 2010 ajoute une clause OrderBy par défaut qui trie par type de contenu, ce qui garantit que les dossiers sont retournés avant les éléments de liste. Sauf si vous remplacez ce comportement par une des trois clauses OrderBy indiquées ci-dessus, votre requête ne peut pas tirer pleinement parti de l’utilisation des champs indexés, et elle sera bloquée lorsque la requête n’est pas conçue pour être suffisamment restrictive pour retourner un nombre d’éléments inférieur au nombre maximum. L’exemple de code suivant montre comment utiliser la clause ContentIterator.ItemEnumerationOrderByNVPField. L’exemple suppose que vous effectuez une requête sur un champ indexé.

    SPQuery query = new SPQuery();
    query.Query = 
    "<Where><Eq><FieldRef Name=\"MyIndexedField\"/><Value Type=\"Text\">FieldValue</Value></Eq></Where>" 
    + ContentIterator.ItemEnumerationOrderByNVPField;
    ContentIterator ci = new ContentIterator();
    ci.ProcessItemsInList(query,
        delegate(SPListItem item)
        {
            // Work on each item.
        },
        delegate(SPListItem item, Exception e)
        {
            // Handle an exception that was thrown while iterating.
            // Return true so that ContentIterator rethrows the exception.
            return true;
        }
    );
    
    Dim query As New SPQuery()
    query.Query = "<Where><Eq><FieldRef Name=""MyIndexedField""/><Value Type=""Text"">FieldValue</Value></Eq></Where>" & ContentIterator.ItemEnumerationOrderByNVPField
    Dim ci As New ContentIterator()
    ci.ProcessItemsInList(query,
                                  Function(item As SPListItem)
                                      'Work on each item.
                                  End Function,
                                  Function(item As SPListItem, e As Exception)
                                      'Handle an exception that was thrown while iterating.
                                      'Return true so that ContentIterator rethrows the exception.
                                      Return True
                                  End Function)
    

Utilisation de PortalSiteMapProvider

Utilisez PortalSiteMapProvider (Microsoft Office SharePoint Server 2007 et Microsoft SharePoint Server 2010 uniquement).

Le livre blanc de Steve Peschka Utilisation de listes de grande taille dans Office SharePoint Server 2007 (éventuellement en anglais) décrit une approche efficace de la récupération des données de liste à l’aide de la classe PortalSiteMapProvider. PortalSiteMapProvider fournit une infrastructure de mise en cache automatique pour la récupération des données de liste. La méthode GetCachedListItemsByQuery de PortalSiteMapProvider prend un objet SPQuery en tant que paramètre, puis vérifie son cache pour déterminer si les éléments existent déjà. Si c’est le cas, la méthode retourne les résultats mis en cache. Si ce n’est pas le cas, elle interroge la liste et stocke les résultats dans un cache. Cette approche fonctionne particulièrement bien lorsque vous récupérez des données de liste qui ne changent pas considérablement au fil du temps. Lorsque les jeux de données changent fréquemment, la classe augmente les coûts en termes de performance en écrivant continuellement dans le cache, en plus des coûts liés à la lecture de la base de données. Vous devez considérer que la classe PortalSiteMapProvider utilise le cache de l’objet de collection de sites pour stocker des données. Ce cache a une taille par défaut de 100 Mo. Vous pouvez augmenter la taille du cache pour chaque collection de sites sur la page de paramètres de cache de l’objet pour la collection de sites. Cette mémoire provient cependant de la mémoire partagée disponible pour le pool d’applications et peut donc affecter les performances d’autres applications. Une autre limitation importante est que vous ne pouvez pas utiliser la classe PortalSiteMapProvider dans les applications basées sur Windows Forms. L’exemple de code suivant montre comment utiliser cette méthode.

Meilleures pratiques de codage

Utilisation de PortalSiteMapProvider

// Get the current SPWeb object. 
SPWeb curWeb = SPControl.GetContextWeb(HttpContext.Current); 

// Create the query. 
SPQuery curQry = new SPQuery(); 
curQry.Query = "<Where><Eq><FieldRef Name='Expense_x0020_Category'/>
<Value Type='Text'>Hotel</Value></Eq></Where>"; 

// Create an instance of PortalSiteMapProvider. 
PortalSiteMapProvider ps = PortalSiteMapProvider.WebSiteMapProvider; 
PortalWebSiteMapNode pNode = ps.FindSiteMapNode(curWeb.ServerRelativeUrl) as PortalWebSiteMapNode; 

// Retrieve the items. 

SiteMapNodeCollection pItems = ps.GetCachedListItemsByQuery(pNode, "myListName_NotID", curQry, curWeb); 

// Enumerate through all of the matches. 
foreach (PortalListItemSiteMapNode pItem in pItems)
   { 
   // Do something with each match.
   }
' Get the current SPWeb object. 
Dim curWeb As SPWeb = SPControl.GetContextWeb(HttpContext.Current)

' Create the query. 
Dim curQry As New SPQuery()
curQry.Query = "<Where><Eq><FieldRef Name='Expense_x0020_Category'/> <Value Type='Text'>Hotel</Value></Eq></Where>"

' Create an instance of PortalSiteMapProvider. 
Dim ps As PortalSiteMapProvider = PortalSiteMapProvider.WebSiteMapProvider
Dim pNode As PortalWebSiteMapNode = TryCast(ps.FindSiteMapNode(curWeb.ServerRelativeUrl), PortalWebSiteMapNode)

' Retrieve the items. 

Dim pItems As SiteMapNodeCollection = ps.GetCachedListItemsByQuery(pNode, "myListName_NotID", curQry, curWeb)

' Enumerate through all of the matches. 
For Each pItem As PortalListItemSiteMapNode In pItems
   ' Do something with each match.
Next pItem