Pull to refresh

Получаем SPListItem из SPList. Очень быстро и очень медленно

Reading time 3 min
Views 5.1K
При профилировании веб-части для SharePoint с удивлением обнаружил узкое место в SPListItemCollection.this[Guid]… Получение элемента списка по Guid'у, фактически первичному ключу, занимало уйму времени на большой коллекции.
Происходило это так

var uniqId = new Guid(/* get GUID somehow */);
SPList list = /* get list somehow */

SPListItem anItem = list.Items[uniqId];


* This source code was highlighted with Source Code Highlighter.
Как есть еще методы получения элемента из списка?
Есть SPList.GetItemByUniqueId(Guid uniqueId) — при использовании не возникает такой задержки. Почему?

Воспользуемся рефлектором, и пореверсинженерим шарепонит…

Вот что мы видим в SPListItemCollection.this[Guid]:

public SPListItem this[Guid uniqueId]
{
  get
  {
    this.EnsureListItemsData();
    this.EnsureFieldMap();
    int iIndex = 0;
    int columnNumber = this.m_mapFields.GetColumnNumber("UniqueId");
    string str2 = uniqueId.ToString("B").ToLower();
    while (true)
    {
      if (iIndex >= this.m_iRowCount)
      {
        throw new ArgumentException();
      }
      string str = ((string) this.m_arrItemsData[columnNumber, iIndex]).ToLower();
      int num3 = SPUtility.StsBinaryCompareIndexOf(str, ";#");
      if ((num3 > 0) && (str.Substring(num3 + 2) == str2))
      {
        this.EnsureListItemIsValid(iIndex);
        if (this.m_iColection == null)
        {
          return new SPListItem(this, iIndex);
        }
        return this.m_iColection.ItemFactory(iIndex);
      }
      iIndex++;
    }
  }
}


* This source code was highlighted with Source Code Highlighter.

Содержимое всей коллекции перебирается элемент за элементом, для каждого элемента вычисляется совпадение GUID'а с заданным. Чем больше коллекция — тем дольше работаем.

А теперь GetItemByUniqueId:
public SPListItem GetItemByUniqueId(Guid uniqueId)
{
  SPQuery query = new SPQuery();
  query.Query = "<Where><Eq><FieldRef Name=\"UniqueId\"></FieldRef><Value Type=\"Guid\">" + uniqueId.ToString("B") + "</Value></Eq></Where>";
  query.ViewAttributes = "Scope=\"RecursiveAll\" ModerationType=\"Moderator\"";
  query.MeetingInstanceId = -2;
  query.QueryOpt = SPQuery.SPQueryOpt.None | SPQuery.SPQueryOpt.UniqueId;
  SPListItemCollection items = this.GetItems(query);
  if (items.Count != 0)
  {
    return items[0];
  }
  while (!(this.ID == this.Lists.Web.UserInfoListId))
  {
    throw new ArgumentException();
  }
  throw new ArgumentException(SPResource.GetString("CannotFindUser", new object[0]));
}


* This source code was highlighted with Source Code Highlighter.

Здесь, используя SPQuery, получаем непосредственно саму запись без перебора коллекции.

Вывод: на больших списках пользоваться SPList.Items[Guid] — долго, непроизводительно. Лучше предпочесть SPList.getItemByUniqueId(Guid);

UPD: Спасибо vladem — полезная линка на тематический KB — http://msdn.microsoft.com/en-us/library/bb687949.aspx
Tags:
Hubs:
+22
Comments 19
Comments Comments 19

Articles