if (this.m_Query.ConsiderManagedPipe && this.m_Query.SafeArrayFlags == null && (this.m_Query.CalendarDate == DateTime.MinValue && !this.m_Query.IncludeMandatoryColumns) && (this.m_Query.ViewFieldsOnly && (this.m_Query.DataTableOptions & SPListGetDataTableOptions.RetrieveLookupIdsOnly) != SPListGetDataTableOptions.None && ((this.m_Query.DataTableOptions & SPListGetDataTableOptions.UseBooleanDataType) != SPListGetDataTableOptions.None && (this.m_Query.DataTableOptions & SPListGetDataTableOptions.UseCalculatedDataType) != SPListGetDataTableOptions.None)) && (!string.IsNullOrEmpty(this.m_Query.ViewFields) && string.IsNullOrEmpty(this.m_Query.ViewAttributes) && (this.m_List.BaseType != SPBaseType.DiscussionBoard && !this.QueryIncludesMultiValueLookup(this.m_Query.ViewFields)) && !this.m_List.HasUniqueScopes)) { ULS.SendTraceTag(963012918U, (ULSCatBase) ULSCat.msoulscat_WSS_Database, ULSTraceLevel.Verbose, "SPListItemCollection.EnsureListItemData: Retrieving data through the managed pipe."); this.m_bUseManagedPipe = true; }
Интересно, думаю. Неспроста! Сами посмотрите: условия все такие, логически связанные с performance. Может это какой-нибудь хитрый performance-boost такой?
Ну, начал разбираться...
Оказалось, единственное использование internal-свойста ConsiderManagedPipe - в private методе GetItemsForDataTable, который в свою очередь вызывается уже из публичных методов - GetDataTable и AppendDataTable:
// xref: GetDataTable // xref: AppendDataTable private SPListItemCollection GetItemsForDataTable(SPQuery query, SPListGetDataTableOptions flags) { query.ViewFieldsOnly = true; query.ConsiderManagedPipe = true; query.DataTableOptions = flags; return this.GetItems(query); }
Соответственно, начал думать про этот SPList.GetDataTable. На удивление, я его ни разу в жизни не использовал (использовал только SPListItemCollection.GetDataTable). Но если он есть, значит, думаю, зачем-то ведь он нужен! Тем более что обнаружилась какая-то загадочная ветка выполнения запроса SPQuery, которая срабатывала как раз только в случае вызова SPList.GetDataTable! Поэтому решил потестить на производительность. Нагенерил элементов в список:
И собрал вот такой вот простенький PS-скрипт:
$w = get-spweb http://localhost $l = $w.Lists["Tasks"] $q = new-object Microsoft.SharePoint.SPQuery $q.Query = '<Where><And><Lt><FieldRef Name="PercentComplete" /><Value Type="Number">1</Value></Lt><And><Neq><FieldRef Name="AssignedTo" LookupId="True" /><Value Type="Integer">3</Value></Neq><And><Eq><FieldRef Name="Priority" /><Value Type="Text">(3) Low</Value></Eq><Contains><FieldRef Name="Title" /><Value Type="Text">Prep</Value></Contains></And></And></And></Where>'; $q.ViewFields='<FieldRef Name="Title" /><FieldRef Name="DueDate" /><FieldRef Name="AssignedTo" />'; $pos = $null (Measure-Command { $ii = $l.GetItems($q); $ii[0]; $ii.Count }).TotalMilliseconds (Measure-Command { $dt = $l.GetDataTable($q, [Microsoft.SharePoint.SPListGetDataTableOptions]0, [ref] $pos); $dt.Rows[0]; $dt.Rows.Count }).TotalMilliseconds (Measure-Command { $dt = $l.GetDataTable($q, [Microsoft.SharePoint.SPListGetDataTableOptions]::RetrieveLookupIdsOnly -bor [Microsoft.SharePoint.SPListGetDataTableOptions]::UseBooleanDataType -bor [Microsoft.SharePoint.SPListGetDataTableOptions]::UseCalculatedDataType, [ref] $pos); $dt.Rows[0]; $dt.Rows.Count }).TotalMilliseconds
Конечно, если запускать GetItems и GetDataTable'ы последовательно, после первого запроса врубается кэш. Поэтому пришлось мерять по отдельности, и старательно закрывать окошко PS после каждого одиночного теста.
Результаты в среднем получились примерно такие:
Надпись о том, что во втором случае используются managed pipes, в логи успешно валилась. Правда, скорости это не прибавляло :(
Конечно, очень хотелось, чтобы этот загадочный GetDataTable оказался полезным. Поэтому я упорно продолжал тестить на разных объемах данных, с разными выборками, с разными по сложности запросами. Все одно и то же: хотя цифры скачут на +/-200мс, GetItems почти всегда на 150-300мс быстрее. Даже из-под кэша.
Так что вот такой вот в недрах SharePoint есть загадочно бесполезный код :) Не знаю даже, зачем он нужен :)...
Андрей, Здравствуйте!Хочу сразу сказать спасибо за ваши труды))
ОтветитьУдалитьНасчет GetDataTable ...https://msdn.microsoft.com/ru-ru/library/bb687949%28v=office.12%29.aspx?f=255&MSPPError=-2147217396
SPListItemCollection - как я понял не является потокобезопасным, поэтому можно кэшировать объект DataTable
public void CacheData()
{
DataTable oDataTable;
SPListItemCollection oListItems;
lock(this)
{
oDataTable = (DataTable)Cache["ListItemCacheName"];
if(oDataTable == null)
{
oListItems = DoQueryToReturnItems();
oDataTable = oListItems.GetDataTable();
Cache.Add("ListItemCacheName", oDataTable, ..);
}
}
}