Schreiben von effizientem Code in SharePoint Server

Letzte Änderung: Montag, 30. November 2009

Gilt für: SharePoint Server 2010

Wenn Sie benutzerdefinierte Lösungen mithilfe des SharePoint-Objektmodells schreiben, sollten Ihnen einige Probleme hinsichtlich Leistung, Erweiterbarkeit und Skalierbarkeit bekannt sein. Die Informationen in diesem Thema können Ihnen helfen, Probleme bei vorhandenen SharePoint-Anwendungen effektiv zu beheben, die Leistung dieser Anwendungen zu steigern oder neue SharePoint-Anwendungen zu schreiben. In allen Fällen müssen Sie wissen, was Sie tun können, um das SharePoint-Objektmodell effizient zu nutzen, und wie Sie allgemeine Programmiertechniken speziell für die SharePoint-Plattform einsetzen.

Verwenden von "SPQuery"-Objekten

Mit gut durchdachten Abfragen können Sie Leistungsprobleme vermeiden, die bei wachsender Größe der Listen und Ordner auf Ihrer Website im Laufe der Zeit auftreten können. Mithilfe der folgenden Techniken können Sie SPQuery-Objekte besonders effizient einsetzen.

  • Verwenden Sie ein begrenztes SPQuery-Objekt.

    Bei einer SPQuery ohne einen Wert für RowLimit wird die Leistung schlecht sein, und bei umfangreichen Listen werden Fehler auftreten. Geben Sie ein RowLimit zwischen 1 und 2000 ein, und blättern Sie ggf. durch die Liste. Ein Codebeispiel, in dem dies veranschaulicht wird, finden Sie unter Arbeiten mit umfangreichen Ordnern und Listen.

  • Begrenzen Sie das Resultset.

    Wenn die Abfrage mehr Elemente zurückgibt, als im Abfrageschwellenwert in Microsoft SharePoint Foundation 2010 konfiguriert, wird die Abfrage blockiert und Sie erhalten keine Ergebnisse. Der Standardschwellenwert für Abfragen lautet 5.000 Elemente. Sie können jedoch einen niedrigeren Wert festlegen. Verwenden Sie für Microsoft SharePoint Server 2010-Abfragen ContentIterator.MaxItemsPerQuery, und blättern Sie durch die Ergebnisse, wenn Sie alle Elemente benötigen.

  • Verwenden Sie indizierte Felder.

    Wenn Sie eine Abfrage für ein nicht indiziertes Feld ausführen und bei der daraus resultierenden Überprüfung mehr Elemente in der Liste gefunden werden, als gemäß Abfrageschwellenwert zulässig, wird die Abfrage blockiert. Legen Sie SPQuery.RowLimit auf einen Wert unterhalb des Abfrageschwellenwerts fest. Der Wert von ContentIterator.MaxItemsPerQuery muss kleiner oder gleich dem Schwellenwert sein, der der empfohlene Wert für SharePoint Server 2010 ist.

  • Achten Sie darauf, dass Sie eine der drei OrderBy-Klauseln einschließen –ContentIterator.ItemEnumerationOrderByID, ContentIterator.ItemEnumerationOrderByPath oder ContentIterator.ItemEnumerationOrderByNVPField –, die die Verwendung des Indexes ermöglichen.

    Ohne eine OrderBy-Klausel wird die Abfrage möglicherweise blockiert. SharePoint Server 2010 fügt eine Standard-OrderBy-Klausel hinzu, die die Elemente nach Inhaltstyp sortiert. Dadurch werden Ordner vor Listenelementen zurückgegeben. Wenn Sie dieses Verhalten nicht mit einer der drei oben genannten OrderBy-Klauseln außer Kraft setzen, kann die Abfrage die Verwendung von indizierten Feldern nicht voll nutzen, und die Abfrage wird immer dann blockiert, wenn sie nicht so restriktiv formuliert wurde, dass sie weniger als die maximale Anzahl von Elementen zurückgibt. Im folgenden Codebeispiel wird die Verwendung der ContentIterator.ItemEnumerationOrderByNVPField-Klausel veranschaulicht. Bei dem Beispiel wird davon ausgegangen, dass Sie eine Abfrage für ein indiziertes Feld ausführen.

    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)
    

Verwenden von "PortalSiteMapProvider"

Verwenden Sie PortalSiteMapProvider (nur Microsoft Office SharePoint Server 2007 und Microsoft SharePoint Server 2010).

Im Whitepaper Arbeiten mit großen Listen in Office SharePoint Server 2007 beschreibt Steve Peschka eine effiziente Technik zum Abrufen von Listendaten mithilfe der PortalSiteMapProvider-Klasse. PortalSiteMapProvider stellt eine Infrastruktur für die automatische Zwischenspeicherung zum Abrufen von Listendaten bereit. Die GetCachedListItemsByQuery-Methode von PortalSiteMapProvider nimmt ein SPQuery-Objekt als Parameter an und überprüft dann dessen Zwischenspeicher, um zu ermitteln, ob die Elemente bereits vorhanden sind. Ist dies der Fall, gibt die Methode die zwischengespeicherten Ergebnisse zurück. Andernfalls fragt sie die Liste ab und speichert die Ergebnisse in einem Zwischenspeicher. Dies funktioniert besonders gut, wenn Sie Listendaten abrufen, die sich im Laufe der Zeit nur unwesentlich ändern. Wenn Datensets sich häufig ändern, kommt es bei der Klasse zu Leistungseinbußen durch das ständige Schreiben in den Cache und das Lesen aus der Datenbank. Denken Sie daran, dass die PortalSiteMapProvider-Klasse den Websitesammlungsobjekt-Cache zum Speichern von Daten verwendet. Dieser Cache hat eine Standardgröße von 100 MB. Sie können die Größe dieses Caches für jede Websitesammlung auf der Seite Einstellungen für den Objektcache für die Websitesammlung erhöhen. Allerdings wird dieser Arbeitsspeicher von dem gemeinsam genutzten Arbeitsspeicher "abgezweigt", der dem Anwendungspool zur Verfügung steht, was zu einer Beeinträchtigung der Leistung anderer Anwendungen führen kann. Eine weitere bedeutende Einschränkung besteht darin, dass Sie die PortalSiteMapProvider-Klasse nicht in Anwendungen verwenden können, die auf Windows Forms basieren. Im folgenden Codebeispiel wird die Verwendung dieser Methode gezeigt.

Bewährte Codierungstechnik

Verwenden von 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