Tratamiento de carpetas y listas de gran tamaño
Última modificación: viernes, 10 de junio de 2011
Hace referencia a: SharePoint Foundation 2010
En este artículo
Limitación de consultas de listas de gran tamaño
Trabajar con carpetas y listas
Eliminación de varias versiones de un elemento de lista
Cuando aumenta el tamaño de las carpetas y las listas, debe diseñar código personalizado que funcione con ellas para optimizar el rendimiento. En caso contrario, las aplicaciones se ejecutarán lentamente y podrían causar tiempos de espera de carga de páginas o servicios. Las dos áreas principales de preocupación al trabajar con listas y carpetas de gran tamaño son las siguientes:
La limitación de consultas, que puede provocar que el comportamiento del código cambie de maneras inesperadas e imprevisibles a lo largo del tiempo, a medida que el sitio evoluciona y las consultas comienzan a devolver elementos que exceden el umbral de consultas.
La recuperación eficiente de elementos de listas y carpetas de gran tamaño.
Para solucionar ambos problemas, debe comprender cómo interactúa el modelo de objetos con las carpetas y listas.
Limitación de consultas de listas de gran tamaño
Microsoft SharePoint Foundation 2010 y Microsoft SharePoint Server 2010 aplican un umbral de consultas predeterminado de 5.000 elementos. Cualquier código personalizado que se base en conjuntos de resultados de consulta que puedan superar este máximo no podrá funcionar de acuerdo a lo esperado. Las consultas en listas que constan de más de 5.000 elementos que incluyen campos que no están indizados en sus condiciones de consulta también generarán un error, porque esas consultas deben analizar todas las filas de una lista. Siga los pasos enumerados a continuación para ver y aumentar este límite o para permitir que el modelo de objetos lo invalide:
Para ver y aumentar este umbral o para permitir que el modelo de objetos lo invalide
En el sitio Administración central, en Administración de aplicaciones, haga clic en Administrar aplicaciones web.
Haga clic en Configuración general y, a continuación, en Limitación de recursos.
Vea y actualice el umbral o permita que el modelo de objetos invalide el límite.
Trabajar con carpetas y listas
Las recomendaciones siguientes para solucionar problemas de rendimiento cuando se trabaja con listas y carpetas de gran tamaño se basan en los resultados de las pruebas informados en las notas del producto de Steve Peschka sobre trabajar con listas de gran tamaño en Office SharePoint Server 2007. Estas recomendaciones también se aplican a Microsoft SharePoint Server 2010. Para obtener instrucciones adicionales sobre el uso de SPQuery y la clase PortalSiteMapProvider, que se aplica específicamente a SharePoint Server 2010, consulte Escritura de código eficiente en SharePoint Server.
Cuando trabaja con carpetas y listas:
No use SPList.Items.
SPList.Items selecciona todos los elementos de todas las subcarpetas, incluidos todos los campos de la lista. Use las siguientes alternativas para cada caso de uso.
Agregar un elemento
En lugar de llamar a SPList.Items.Add, use SPList.AddItem.
Recuperación de todos los elementos de una lista
En lugar de usar SPList.Items, use SPList.GetItems(SPQuery query) . Aplique filtros, si corresponde, y especifique solo los campos que necesite para que la consulta sea más eficiente. Si la lista contiene más de 2.000 elementos, pagine la lista en incrementos de no más de 2.000 elementos. En el ejemplo de código siguiente se muestra cómo paginar una lista de gran tamaño.
Procedimiento recomendado de codificación
Recuperación de elementos con 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
En el ejemplo siguiente se muestra cómo enumerar y paginar una lista de gran tamaño.
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
Obtención de elementos por identificador
En lugar de usar SPList.Items.GetItemById, use SPList.GetItemById(int id, string field1, params string[] fields). Especifique el identificador del elemento y el campo que desee.
No enumere las colecciones SPList.Items o colecciones SPFolder.Files completas.
La columna izquierda en la Tabla 1 enumera las propiedades y los métodos que, si se usan, enumerarán la colección SPList.Items completa, y provocarán un rendimiento y limitación deficientes para las listas de gran tamaño. En su lugar, use las alternativas con mejor rendimiento que se enumeran en la columna de la derecha.
Tabla 1. Alternativas para enumerar SPList.Items
Métodos y propiedades con rendimiento deficiente
Alternativas con mejor rendimiento
SPList.Items.Count
SPList.ItemCount
SPList.Items.XmlDataSchema
Creación de un objeto SPQuery para recuperar sólo los elementos que desee.
SPList.Items.NumberOfFields
Creación de un objeto SPQuery (especificando ViewFields) para recuperar solo los elementos que desee.
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)
Realización de una consulta paginada mediante SPQuery y reordenación de los elementos dentro de cada página.
SPList.Items.ListItemCollectionPosition
ContentIterator.ProcessListItems(SPList, ContentIterator.ItemProcessor, ContentIterator.ItemProcessorErrorCallout) (solo Microsoft SharePoint Server 2010)
SPList.Items.ListItemCollectionPosition
ContentIterator.ProcessListItems(SPList, ContentIterator.ItemProcessor, ContentIterator.ItemProcessorErrorCallout) (solo SharePoint Server 2010)
Nota
Se recomienda usar la propiedad SPList.ItemCount para recuperar el número de elementos de una lista. Como efecto secundario de la optimización de esta propiedad para mejorar el rendimiento, no obstante, la propiedad ocasionalmente puede devolver resultados inesperados. Por ejemplo, si necesita el número exacto de elementos, debe usar la propiedad con rendimiento deficiente GetItems(SPQuery query), como se muestra en el ejemplo de código anterior.
Siempre que sea posible, debe adquirir una referencia a una lista mediante el GUID de la lista o la dirección URL como una clave.
Puede recuperar un objeto SPList de la propiedad SPWeb.Lists mediante el uso del GUID o nombre para mostrar de la lista como un indizador. Siempre es preferible usar SPWeb.Lists[GUID] y SPWeb.GetList(strURL) en lugar de SPWeb.Lists[strDisplayName]. Es preferible usar el GUID porque es único, permanente y requiere solo una única búsqueda en la base de datos. El indizador de nombre para mostrar recupera los nombres de todas las listas del sitio y después realiza una comparación de cadenas con ellos. Si tiene una dirección URL de lista en lugar de un GUID, puede usar el método GetList de SPWeb para buscar el GUID de la lista en la base de datos de contenido antes de recuperar la lista.
No enumere colecciones SPFolder.Files completas.
La columna izquierda en la Tabla 2 enumera las propiedades y los métodos que inflan la colección SPFolder.Files, y provocan un rendimiento y limitación deficientes para las listas de gran tamaño. En su lugar, use las alternativas con mejor rendimiento de la columna de la derecha.
Tabla 2. Alternativas para SPFolders.Files
Métodos y propiedades con rendimiento deficiente
Alternativas con mejor rendimiento
SPFolder.Files.Count
SPFolder.ItemCount
SPFolder.Files.GetEnumerator()
ContentIterator.ProcessFilesInFolder(SPFolder, System.Boolean, ContentIterator.FileProcessor, ContentIterator.FileProcessorErrorCallout) (solo SharePoint Server 2010)
SPFolder.Files[System.String]
ContentIterator.GetFileInFolder(SPFolder, System.String) Como alternativa, SPFolder.ParentWeb.GetFile(SPUrlUtility.CombineUrl(SPFolder.Url, System.String) (solo SharePoint Server 2010)
SPFolder.Files[System.Int32]
No usar. Cambie a ContentIterator.ProcessFilesInFolder y cuente los elementos durante la iteración. (Solo SharePoint Server 2010)
Eliminación de varias versiones de un elemento de lista
Cuando elimine varias versiones de un elemento de lista, use el método DeleteByID(); no use el método Delete(). Experimentará problemas de rendimiento si elimina cada objeto SPListItemVersion de un objeto SPListItemVersionCollection. El procedimiento recomendado es crear una matriz que tenga las propiedades del identificador de cada versión y, a continuación, eliminar cada versión con el método SPFileVersionCollection.DeleteByID. En los siguientes ejemplos de código se muestra el enfoque que no se recomienda y el enfoque recomendado para eliminar todas las versiones del primer elemento de una lista personalizada.
Procedimiento no recomendado de codificación
Eliminación de cada objeto SPListItemVersion
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);
}
}
Procedimiento recomendado de codificación
Eliminación de todas las versiones de un elemento de lista usando el método SPFileVersionCollection.DeleteByID
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);
}
}
Si elimina las versiones de los elementos de una biblioteca de documentos, puede usar un enfoque similar mediante la recuperación de la propiedad SPListItem.File.Versions, como se muestra en el siguiente ejemplo de código.
Procedimiento recomendado de codificación
Eliminación de todas las versiones de un elemento de lista de una biblioteca de documentos usando el método SPFileVersionCollection.DeleteByID
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);
}
}