При профилировании веб-части для SharePoint с удивлением обнаружил узкое место в SPListItemCollection.this[Guid]… Получение элемента списка по Guid'у, фактически первичному ключу, занимало уйму времени на большой коллекции.
Происходило это так
Есть SPList.GetItemByUniqueId(Guid uniqueId) — при использовании не возникает такой задержки. Почему?
Воспользуемся рефлектором, и пореверсинженерим шарепонит…
Вот что мы видим в SPListItemCollection.this[Guid]:
Содержимое всей коллекции перебирается элемент за элементом, для каждого элемента вычисляется совпадение GUID'а с заданным. Чем больше коллекция — тем дольше работаем.
А теперь GetItemByUniqueId:
Здесь, используя SPQuery, получаем непосредственно саму запись без перебора коллекции.
Вывод: на больших списках пользоваться SPList.Items[Guid] — долго, непроизводительно. Лучше предпочесть SPList.getItemByUniqueId(Guid);
UPD: Спасибо vladem — полезная линка на тематический KB — http://msdn.microsoft.com/en-us/library/bb687949.aspx
Происходило это так
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