Написание эффективного кода в SharePoint Server

Дата последнего изменения: 30 ноября 2009 г.

Применимо к: SharePoint Server 2010

При написании собственных решений с помощью объектной модели SharePoint необходимо учитывать некоторые распространенные проблемы, связанные с производительностью, расширяемостью и масштабируемостью. Данный раздел содержит сведения, которые помогут провести эффективную диагностику и повысить производительность имеющихся приложений SharePoint либо написать новые приложения. В любом случае необходимо понимать принципы эффективной работы объектной модели SharePoint и применения общих методик программирования к платформе SharePoint.

Использование объектов SPQuery

Правильное проектирование запросов поможет избежать проблем производительности, которые могут возникнуть по мере роста размера списков и папок сайта. Следующие приемы позволят вам наиболее эффективно использовать объекты SPQuery.

  • Использование связанного объекта SPQuery.

    Запрос SPQuery, не имеющий значения для параметра RowLimit, будет иметь низкую производительность и не будет работать в крупных списках. Укажите значение параметра RowLimit от 1 до 2000 и пролистывание списка. Пример кода, демонстрирующий эти настройки, см. в разделе Обработка больших папок и списков.

  • Ограничение набора результатов.

    Если запрос возвращает больше элементов, чем задано в пороговом значении запроса в Microsoft SharePoint Foundation 2010, запрос будет заблокирован и результаты выводиться не будут. Пороговое значение запроса по умолчанию — 5000 элементов, но можно задать меньшее количество. Для запросов Microsoft SharePoint Server 2010 используйте ContentIterator.MaxItemsPerQuery и пролистывание набора результатов для просмотра всех элементов.

  • Использование индексированных полей.

    При отправке запроса в неиндексированное поле и обнаружении в списке большего количества элементов, чем задано в пороговом значении запроса, запрос будет заблокирован. Задайте для параметра SPQuery.RowLimit значение, не превышающее пороговое значение запроса. Необходимо убедиться, что значение параметра ContentIterator.MaxItemsPerQuery меньше или равно пороговому значению запроса. Это значение является рекомендуемым для SharePoint Server 2010.

  • Для разрешения использования индекса необходимо включить одно из следующих трех предложений OrderBy: ContentIterator.ItemEnumerationOrderByID, ContentIterator.ItemEnumerationOrderByPath или ContentIterator.ItemEnumerationOrderByNVPField.

    В отсутствие предложения OrderBy запрос может блокироваться. В SharePoint Server 2010 добавлено предложение по умолчанию OrderBy, которое упорядочивает элементы по типу контента, что обеспечивает возвращение папок прежде элементов списка. Если не переопределить это значение с помощью одного из трех указанных выше предложений OrderBy, запрос не сможет использовать все преимущества индексированных полей и будет блокироваться, если не будет обеспечивать достаточных ограничений для возврата количества элементов, не превышающего максимальное. Приведенный ниже пример кода демонстрирует использование предложения ContentIterator.ItemEnumerationOrderByNVPField. Пример предполагает отправку запроса в индексированное поле.

    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)
    

Использование класса PortalSiteMapProvider

Использование PortalSiteMapProvider (только в Microsoft Office SharePoint Server 2007 и Microsoft SharePoint Server 2010).

В техническом документе Стива Пешки (Steve Peschka) Работа с большими списками в системе Office SharePoint Server 2007 (Возможно, на английском языке) описывается эффективная методика получения данных списка с помощью класса PortalSiteMapProvider. Класс PortalSiteMapProvider обеспечивает автоматическую инфраструктуру кэширования для извлечения данных списка. Метод GetCachedListItemsByQuery класса PortalSiteMapProvider принимает объект SPQuery в качестве параметра, затем проверяет его кэш для выявления наличия элементов. Если элементы уже существуют, метод возвращает кэшированные результаты. Если элементы не существуют, он отправляет запрос в список и сохраняет результаты в кэш. Эта методика особенно эффективна при получении данных списка, которые редко изменяются. Если наборы данных подвержены частым изменениям, производительность класса страдает в связи с необходимостью постоянной записи в кэш помимо считывания данных из базы данных. Учтите, что класс PortalSiteMapProvider использует для хранения данных кэш объектов семейства сайтов. Размер этого кэша по умолчанию составляет 100 МБ. Увеличить размер кэша можно для каждого семейства сайтов на странице параметров объектного кэша для данного семейства сайтов. Однако следует учесть, что эта память — часть общей памяти, доступной пулу приложений, и поэтому увеличение размера кэша может повлиять на производительность других приложений. Еще одно серьезное ограничение состоит в том, что класс PortalSiteMapProvider нельзя использовать в приложениях, основанных на Windows Forms. Следующий пример кода демонстрирует использование этого метода.

Практическая рекомендация по кодированию

Использование класса 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