Escritura de código eficiente en SharePoint Server
Última modificación: lunes, 30 de noviembre de 2009
Hace referencia a: SharePoint Server 2010
Si escribe soluciones personalizadas mediante el modelo de objetos de SharePoint, debe tener en cuenta problemas comunes en relación con el rendimiento, la extensibilidad y la escalabilidad. Este tema puede ser útil para resolver problemas y mejorar de manera eficaz el rendimiento de las aplicaciones existentes de SharePoint, o bien para escribir nuevas aplicaciones de SharePoint. En ambos casos, es necesario comprender cómo lograr que el modelo de objetos de SharePoint funcione correctamente y cómo aplicar técnicas generales de programación a la plataforma de SharePoint específicamente.
Uso de objetos SPQuery
Las consultas bien diseñadas pueden ayudarle a evitar problemas de rendimiento que pueden producirse con el tiempo a medida que aumenta el tamaño de las listas y carpetas del sitio. Las siguientes técnicas pueden ser útiles para usar los objetos SPQuery de la manera más eficaz posible.
Use un objeto SPQuery enlazado.
Un objeto SPQuery sin un valor para RowLimit tendrá un rendimiento regular o con errores en listas grandes. Especifique un valor entre 1 y 2000 para RowLimit y, si es necesario, desplácese por la lista. Para ver un ejemplo de código donde se muestre cómo hacer esto, vea Tratamiento de carpetas y listas de gran tamaño.
Limite el conjunto de resultados.
Si una consulta devuelve una cantidad de elementos superior al umbral de consultas configurado en Microsoft SharePoint Foundation 2010, la consulta se bloqueará y no se obtendrán resultados. El umbral de consultas predeterminado es de 5000 elementos, pero puede establecerse en un valor inferior. Para consultas de Microsoft SharePoint Server 2010, use ContentIterator.MaxItemsPerQuery y, si necesita todos los elementos, desplácese por los resultados.
Use campos indizados.
Si realiza una consulta en un campo no indizado y la búsqueda encuentra elementos en la lista que superan el umbral de consultas, la consulta se bloqueará. Establezca SPQuery.RowLimit en un valor inferior a este umbral. Se garantiza que el valor de ContentIterator.MaxItemsPerQuery es inferior o igual al umbral, que es el valor recomendado para SharePoint Server 2010.
Asegúrese de incluir una de las tres cláusulas OrderBy: ContentIterator.ItemEnumerationOrderByID, ContentIterator.ItemEnumerationOrderByPath o ContentIterator.ItemEnumerationOrderByNVPField, que habilitan el uso del índice.
Sin una cláusula OrderBy, podría bloquearse la consulta. SharePoint Server 2010 agrega una cláusula OrderBy predeterminada que ordena por tipo de contenido, lo que garantiza que las carpetas se devuelvan antes que los elementos de la lista. A menos que invalide este comportamiento mediante una de las tres cláusulas OrderBy mencionadas anteriormente, la consulta no podrá aprovechar todos los beneficios del uso de campos indizados y se bloqueará siempre que no esté diseñada de un modo lo suficientemente restrictivo como para devolver una cantidad de elementos inferior a la cantidad máxima establecida. El siguiente código de ejemplo muestra cómo usar la cláusula ContentIterator.ItemEnumerationOrderByNVPField. En el ejemplo se supone que está consultando un campo indizado.
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)
Uso de PortalSiteMapProvider
Use PortalSiteMapProvider (Microsoft Office SharePoint Server 2007 y Microsoft SharePoint Server 2010, únicamente).
En las notas del producto sobre cómo trabajar con listas grandes en Office SharePoint Server 2007, Steve Peschka describe un método eficaz para recuperar datos de una lista mediante el uso de la clase PortalSiteMapProvider. PortalSiteMapProvider proporciona una infraestructura de almacenamiento en caché automático para recuperar datos de la lista. El método GetCachedListItemsByQuery de PortalSiteMapProvider toma un objeto SPQuery como parámetro y, a continuación, comprueba si los elementos ya existen en la memoria caché. Si existen, el método devuelve los resultados almacenados en caché. Si no existen, el método consulta la lista y almacena los resultados en una memoria caché. Este método funciona especialmente bien cuando se recuperan datos de una lista que no cambia considerablemente con el tiempo. Cuando los conjuntos de datos cambian con frecuencia, la clase incurre en un costo de rendimiento al tener que escribir continuamente en la memoria caché, además de leer en la base de datos. Tenga en cuenta que la clase PortalSiteMapProvider usa la memoria caché de objetos de la colección de sitios para almacenar datos. Esta memoria tiene un tamaño predeterminado de 100 MB. El tamaño de la memoria caché puede aumentarse para cada colección de sitios en la página de configuración de la memoria caché de objetos de la colección de sitios. Esta memoria, sin embargo, se toma de la memoria compartida que está disponible para el grupo de aplicaciones y, por lo tanto, afecta al rendimiento de otras aplicaciones. Otra limitación importante es que no se puede usar la clase PortalSiteMapProvider en aplicaciones basadas en Windows Forms. El siguiente ejemplo de código muestra cómo usar este método.
Procedimiento recomendado de codificación
Uso de 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