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
Klicken Sie auf der Website für die Zentraladministration unter Anwendungsverwaltung auf Webanwendungen verwalten.
Klicken Sie auf Allgemeine Einstellungen und dann auf Ressourcensteuerung.
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)
Hinweis
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);
}
}