Arbeiten mit umfangreichen Ordnern und Listen

Letzte Änderung: Freitag, 10. Juni 2011

Gilt für: SharePoint Foundation 2010

Inhalt dieses Artikels
Einschränkung der Abfragen für umfangreiche Listen
Arbeiten mit Ordnern und Listen
Löschen mehrerer Versionen eines Listenelements

Bei zunehmender Größe von Ordnern und Listen müssen Sie zur Optimierung der Leistung benutzerdefinierten Code entwickeln. Andernfalls werden Anwendungen nur langsam ausgeführt und können Timeouts der Dienste oder beim Laden von Seiten zur Folge haben. In erster Linie müssen beim Arbeiten mit umfangreichen Ordnern und Listen die beiden folgenden Bereiche besonders beachtet werden:

  • Abfrageeinschränkung, die im Laufe der Zeit zu unerwartetem und unvorhersehbarem Verhalten von Code führen kann, während sich die Website entwickelt und bei Abfragen Elemente zurückgegeben werden, die über dem Schwellenwert für Abfragen liegen.

  • Effizientes Abrufen von Elementen aus umfangreichen Ordnern und Listen.

Um beiden Aspekten gerecht zu werden, müssen Sie die Interaktion zwischen Objektmodell einerseits und Ordnern und Listen andererseits verstehen.

Einschränkung der Abfragen für umfangreiche Listen

In Microsoft SharePoint Foundation 2010 und Microsoft SharePoint Server 2010 wird für Abfragen ein Standardschwellenwert von 5.000 Elementen angewendet. Benutzerdefinierter Code, in dem Abfrageergebnissätze verwendet werden, die diesen Maximalwert überschreiten können, wird nicht wie erwartet ausgeführt. Bei Abfragen für Listen mit mehr als 5.000 Elementen, die Felder enthalten, deren Abfragebedingungen nicht indiziert sind, treten ebenfalls Fehler auf, da bei diesen Abfragen alle Zeilen in einer Liste durchsucht werden müssen. Führen Sie die nachfolgenden Schritte aus, um diesen Grenzwert anzuzeigen oder zu erhöhen oder um das Objektmodell in die Lage zu versetzen, diesen Grenzwert außer Kraft zu setzen:

So zeigen Sie diesen Schwellenwert an und erhöhen ihn oder versetzen das Objektmodell in die Lage, den Schwellenwert außer Kraft zu setzen

  1. Klicken Sie auf der Website für die Zentraladministration unter Anwendungsverwaltung auf Webanwendungen verwalten.

  2. Klicken Sie auf Allgemeine Einstellungen und dann auf Ressourcensteuerung.

  3. Zeigen Sie den Schwellenwert an und aktualisieren Sie ihn oder lassen Sie zu, dass das Objektmodell den Wert außer Kraft setzt.

Arbeiten mit Ordnern und Listen

Die folgenden Empfehlungen zur Vermeidung von Leistungseinbußen beim Arbeiten mit umfangreichen Ordnern und Listen basieren auf den Testergebnissen, die Steve Peschka in dem Whitepaper Arbeiten mit umfangreichen Listen in Office SharePoint Server 2007 zusammengetragen hat. Diese Empfehlungen gelten auch für Microsoft SharePoint Server 2010. Zusätzliche Hinweise zur Verwendung von SPQuery und der PortalSiteMapProvider-Klasse, die speziell in SharePoint Server 2010 Anwendung findet, finden Sie unter Schreiben von effizientem Code in SharePoint Server.

Beim Arbeiten mit Ordnern und Listen sollten Sie folgende Hinweise beachten:

  • Verwenden Sie SPList.Items nicht.

    Durch SPList.Items werden alle Elemente in allen Unterordnern ausgewählt, einschließlich aller Felder in der Liste. Verwenden Sie die folgenden Alternativen für den jeweiligen Anwendungsfall.

    • Hinzufügen eines Elements

      Anstatt SPList.Items.Add aufzurufen, verwenden Sie SPList.AddItem.

    • Abrufen aller Elemente in einer Liste

      Anstatt SPList.Items aufzurufen, verwenden Sie SPList.GetItems(SPQuery query) . Wenden Sie ggf. Filter an, und geben Sie nur die erforderlichen Felder an, um die Abfrage effizienter auszuführen. Wenn die Liste mehr als 2.000 Elemente enthält, unterteilen Sie die Liste in Einheiten von maximal 2.000 Elementen. Im folgenden Codebeispiel wird die Unterteilung einer umfangreichen Liste veranschaulicht.

      Beispiel für guten Code

      Abrufen von Elementen mithilfe von SPList.GetItems

      SPQuery query = new SPQuery();
      SPListItemCollection spListItems ; 
      string lastItemIdOnPage = null; // Page position.
      int itemCount = 2000
       
      while (itemCount == 2000)
      {
          // Include only the fields you will use.
          query.ViewFields = "<FieldRef Name=\"ID\"/><FieldRef Name=\"ContentTypeId\"/>";   
          query.RowLimit = 2000; // Only select the top 2000.
          // Include items in a subfolder (if necessary).
          query.ViewAttributes = "Scope=\"Recursive\"";
          StringBuilder sb = new StringBuilder();
          // To make the query order by ID and stop scanning the table, specify the OrderBy override attribute.
          sb.Append("<OrderBy Override=\"TRUE\"><FieldRef Name=\"ID\"/></OrderBy>");
          //.. Append more text as necessary ..
          query.Query = sb.ToString();
          // Get 2,000 more items.
       
          SPListItemCollectionPosition pos = new SPListItemCollectionPosition(lastItemIdOnPage);
          query.ListItemCollectionPosition = pos; //Page info.
          spListItems = spList.GetItems(query);
          lastItemIdOnPage = spListItems.ListItemCollectionPosition.PagingInfo;
          // Code to enumerate the spListItems.
          // If itemCount <2000, finish the enumeration.
          itemCount = spListItems.Count;
      
      }
      
      Dim query As New SPQuery()
      Dim spListItems As SPListItemCollection
      Dim lastItemIdOnPage As String = Nothing ' Page position.
      Dim itemCount As Integer = 2000
      
      Do While itemCount = 2000
          ' Include only the fields you will use.
          query.ViewFields = "<FieldRef Name=""ID""/><FieldRef Name=""ContentTypeId""/>"
          query.RowLimit = 2000 ' Only select the top 2000.
          ' Include items in a subfolder (if necessary).
          query.ViewAttributes = "Scope=""Recursive"""
          Dim sb As New StringBuilder()
          ' To make the query order by ID and stop scanning the table, specify the OrderBy override attribute.
          sb.Append("<OrderBy Override=""TRUE""><FieldRef Name=""ID""/></OrderBy>")
          '.. Append more text as necessary ..
          query.Query = sb.ToString()
          ' Get 2,000 more items.
      
          Dim pos As New SPListItemCollectionPosition(lastItemIdOnPage)
          query.ListItemCollectionPosition = pos 'Page info.
          spListItems = spList.GetItems(query)
          lastItemIdOnPage = spListItems.ListItemCollectionPosition.PagingInfo
          ' Code to enumerate the spListItems.
          ' If itemCount <2000, finish the enumeration.
          itemCount = spListItems.Count
      Loop
      

      Im folgenden Beispiel wird die Aufzählung und Unterteilung einer umfangreichen Liste dargestellt.

      SPWeb oWebsite = SPContext.Current.Web;
      SPList oList = oWebsite.Lists["Announcements"];
      
      SPQuery oQuery = new SPQuery();
      oQuery.RowLimit = 10;
      int intIndex = 1;
      
      do
      {
          Response.Write("<BR>Page: " + intIndex + "<BR>");
          SPListItemCollection collListItems = oList.GetItems(oQuery);
      
          foreach (SPListItem oListItem in collListItems)
          {
              Response.Write(SPEncode.HtmlEncode(oListItem["Title"].ToString()) +"<BR>");
          }
      
          oQuery.ListItemCollectionPosition = collListItems.ListItemCollectionPosition;
          intIndex++;
      } while (oQuery.ListItemCollectionPosition != null);
      
       Dim oWebsite As SPWeb = SPContext.Current.Web
      Dim oList As SPList = oWebsite.Lists("Announcements")
      
      Dim oQuery As New SPQuery()
      oQuery.RowLimit = 10
      Dim intIndex As Integer = 1
      
      Do
          Response.Write("<BR>Page: " & intIndex & "<BR>")
          Dim collListItems As SPListItemCollection = oList.GetItems(oQuery)
      
          For Each oListItem As SPListItem In collListItems
              Response.Write(SPEncode.HtmlEncode(oListItem("Title").ToString()) & "<BR>")
          Next oListItem
      
          oQuery.ListItemCollectionPosition = collListItems.ListItemCollectionPosition
          intIndex += 1
      Loop While oQuery.ListItemCollectionPosition IsNot Nothing
      
    • Abrufen von Elementen nach Bezeichnern

      Verwenden Sie SPList.GetItemById(int id, string field1, params string[] fields) anstelle von SPList.Items.GetItemById. Geben Sie den Elementbezeichner und das gewünschte Feld an.

  • Zählen Sie SPList.Items-Auflistungen oder SPFolder.Files-Auflistungen nicht vollständig auf.

    In der linken Spalte von Tabelle 1 werden die Methoden und Eigenschaften aufgeführt, durch die die gesamte SPList.Items-Auflistung aufgezählt wird und die bei umfangreichen Listen zu Leistungseinbußen und Abfrageeinschränkungen führen. Weichen Sie anstelle dessen auf die leistungsoptimierten Alternativen in der rechten Spalte aus.

    Tabelle 1. Alternativen zur Aufzählung von "SPList.Items"

    Methoden und Eigenschaften mit Leistungseinbußen

    Leistungsstärkere Alternativen

    SPList.Items.Count

    SPList.ItemCount

    SPList.Items.XmlDataSchema

    Erstellen Sie ein SPQuery-Objekt, um nur gewünschte Elemente abzurufen.

    SPList.Items.NumberOfFields

    Erstellen Sie ein SPQuery-Objekt (Angabe von ViewFields), um nur gewünschte Elemente abzurufen.

    SPList.Items[System.Guid]

    SPList.GetItemByUniqueId(System.Guid)

    SPList.Items[System.Int32]

    SPList.GetItemById(System.Int32)

    SPList.Items.GetItemById(System.Int32)

    SPList.GetItemById(System.Int32)

    SPList.Items.ReorderItems(System.Boolean[],System.Int32[],System.Int32)

    Führen Sie eine Seitenabfrage mithilfe von SPQuery durch, und sortieren Sie die Elemente auf den einzelnen Seiten neu.

    SPList.Items.ListItemCollectionPosition

    ContentIterator.ProcessListItems(SPList, ContentIterator.ItemProcessor, ContentIterator.ItemProcessorErrorCallout) (nur Microsoft SharePoint Server 2010)

    SPList.Items.ListItemCollectionPosition

    ContentIterator.ProcessListItems(SPList, ContentIterator.ItemProcessor, ContentIterator.ItemProcessorErrorCallout) (nur SharePoint Server 2010)

    HinweisHinweis

    Es wird empfohlen, die SPList.ItemCount-Eigenschaft zum Abrufen der Anzahl der Elemente in einer Liste zu verwenden. Als Nebeneffekt der Leistungsoptimierung dieser Eigenschaft kann es jedoch vorkommen, dass die Eigenschaft gelegentlich unerwartete Ergebnisse zurückgibt. Wenn Sie beispielsweise die genaue Anzahl der Elemente benötigen, sollten Sie die leistungsschwächere GetItems(SPQuery query)-Eigenschaft, wie im vorhergehenden Codebeispiel dargestellt, verwenden.

  • Wenn möglich, besorgen Sie sich einen Verweis auf eine Liste unter Verwendung der GUID oder URL der Liste als Schlüssel.

    Sie können ein SPList-Objekt aus der SPWeb.Lists-Eigenschaft mithilfe der GUID oder des Anzeigenamens der Liste als Index abrufen. Die Verwendung von SPWeb.Lists[GUID] und SPWeb.GetList(strURL) ist der Verwendung von SPWeb.Lists[strDisplayName] immer vorzuziehen. Die Verwendung der GUID ist vorzuziehen, da sie eindeutig und permanent ist und nur eine einzige Datenbanksuche erfordert. Der Anzeigenameindex ruft die Namen aller Listen in der Website ab und führt dann einen Zeichenfolgenvergleich aus. Wenn Sie über eine Listen-URL anstelle einer GUID verfügen, können Sie vor dem Abrufen der Liste mithilfe der GetList-Methode in SPWeb nach der GUID der Liste in der Inhaltsdatenbank suchen.

  • Führen Sie keine Aufzählungen von gesamten SPFolder.Files-Auflistungen durch.

    In der linken Spalte von Tabelle 2 werden die Methoden und Eigenschaften aufgeführt, durch die die SPFolder.Files-Auflistung vergrößert wird und die bei umfangreichen Listen zu Leistungseinbußen und Abfrageeinschränkungen führen. Weichen Sie anstelle dessen auf die leistungsoptimierten Alternativen in der rechten Spalte aus.

    Tabelle 2. Alternativen zu "SPFolders.Files"

    Methoden und Eigenschaften mit Leistungseinbußen

    Leistungsstärkere Alternativen

    SPFolder.Files.Count

    SPFolder.ItemCount

    SPFolder.Files.GetEnumerator()

    ContentIterator.ProcessFilesInFolder(SPFolder, System.Boolean, ContentIterator.FileProcessor, ContentIterator.FileProcessorErrorCallout) (nur SharePoint Server 2010)

    SPFolder.Files[System.String]

    ContentIterator.GetFileInFolder(SPFolder, System.String) Alternativ SPFolder.ParentWeb.GetFile(SPUrlUtility.CombineUrl(SPFolder.Url, System.String) (nur SharePoint Server 2010)

    SPFolder.Files[System.Int32]

    Nicht verwenden. Wechseln Sie zu ContentIterator.ProcessFilesInFolder, und zählen Sie die Elemente während der Iteration. (nurSharePoint Server 2010)

Löschen mehrerer Versionen eines Listenelements

Beim Löschen mehrerer Versionen eines Listenelements sollten Sie die DeleteByID()-Methode verwenden und nicht die Delete()-Methode. Wenn Sie jedes SPListItemVersion-Objekt aus einem SPListItemVersionCollection-Objekt löschen, führt dies zu Leistungsproblemen. Es wird empfohlen, ein Array zu erstellen, das die ID-Eigenschaften aller Versionen enthält, und dann alle Versionen mithilfe der SPFileVersionCollection.DeleteByID-Methode zu löschen. In den folgenden Codebeispielen werden sowohl die nicht empfehlenswerte Vorgehensweise als auch die empfehlenswerte Vorgehensweise zum Löschen aller Versionen des ersten Elements einer benutzerdefinierten Liste vorgestellt.

Beispiel für schlechten Code

Löschen aller SPListItemVersion-Objekte

SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];
SPListItem item = list.GetItemById(1); 
SPListItemVersionCollection vCollection = item.Versions;
ArrayList idList = new ArrayList();
foreach(SPListItemVersion ver in vCollection)
{
  idList.Add(ver.VersionId);
}
foreach(int verID in idList)
{
  SPListItemVersion version = vCollection.GetVersionFromID(verID); 
try
{
  version.Delete();
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);  
}
}

Beispiel für guten Code

Löschen aller Versionen eines Listenelements mithilfe der SPFileVersionCollection.DeleteByID-Methode

SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];
SPListItem item = list.GetItemById(1);
SPFile file = web.GetFile(item.Url);
SPFileVersionCollection collection = file.Versions;
ArrayList idList = new ArrayList();
foreach (SPFileVersion ver in collection)
{
  idList.Add(ver.ID);
}
foreach (int verID in idList)
{
try
{
  collection.DeleteByID(verID);
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);  
}
}

Beim Löschen von Elementversionen in einer Dokumentbibliothek können Sie eine ähnliche Vorgehensweise anwenden, indem Sie die SPListItem.File.Versions-Eigenschaft abrufen, wie im folgenden Codebeispiel dargestellt.

Beispiel für guten Code

Löschen aller Versionen eines Listenelements in einer Dokumentbibliothek mithilfe der SPFileVersionCollection.DeleteByID-Methode

SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];

SPFile file = list.RootFolder.Files[0];
SPFileVersionCollection collection = file.Versions;
ArrayList idList = new ArrayList();
foreach (SPFileVersion ver in collection)
{
  idList.Add(ver.ID);
}
foreach (int verID in idList)
{
try
{
  collection.DeleteByID(verID);
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);  
}
}