Tratamiento de carpetas y listas de gran tamaño

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

    1. En el sitio Administración central, en Administración de aplicaciones, haga clic en Administrar aplicaciones web.

    2. Haga clic en Configuración general y, a continuación, en Limitación de recursos.

    3. 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 . 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; }

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);

    • 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

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

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

C#

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

C#

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

C#

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); } }