Akhil Jain Ответов: 1

Как повысить производительность этого запроса linq ?


у меня есть запрос Linq, который в настоящее время занимает около 15 минут, так как он последовательно вызывает 3 функции, можно ли улучшить производительность этого запроса ?


var results = from myRow in dtTaskandBugs.AsEnumerable()
                          select myRow;
            results.ToList()
             .ForEach(
             r =>
             {
                 r["Storyid"] = GetStoryid(r["Id"]);
                 r["FeatureID"] = Fidname(r["Storyid"]);
                 r["FeatureName"] = r["FeatureID"].ToString() == "0" ? "Anonymous" : fname(r["FeatureID"]);

             });


Что я уже пробовал:

у меня есть запрос Linq, который в настоящее время занимает около 15 минут, так как он последовательно вызывает 3 функции, можно ли улучшить производительность этого запроса ?

var results = from myRow in dtTaskandBugs.AsParallel()
                              select myRow;
                results.ForAll(async r =>
                {
                    Task<int> storyProcessing = GetStoryid(r["Id"]);
                    Task<int> fidProcessing = Fidname(r["Storyid"]);
                    Task<string> featureProcessing = r["FeatureID"].ToString() == "0" ? Task.FromResult("Anonymous") : fname(r["FeatureID"]);
                    r["Storyid"] = await storyProcessing;
                    r["FeatureID"] = await fidProcessing;
                    r["FeatureName"] = await featureProcessing;
                });


        public async Task<int> GetStoryid(object _TbId)
            {
                Task<int> processing = Task.Run(() => {
                    string _wiql =
    String.Format("SELECT [System.Id],[System.Title] " +
    "FROM WorkItemLinks WHERE  ([Source].[System.WorkItemType] = 'Product Backlog Item') " +
    "And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') And ([Target].[System.Id] = {0}  " +
    "AND  [Target].[System.WorkItemType] = 'Task')" +
    " ORDER BY [System.Id] mode(Recursive,ReturnMatchingChildren)", _TbId);


                    Microsoft.TeamFoundation.WorkItemTracking.Client.Query _query = new Microsoft.TeamFoundation.WorkItemTracking.Client.Query(_workitemstore, _wiql);
                    WorkItemLinkInfo[] _links = _query.RunLinkQuery();
                    if (_links.Count() == 2) //only 1 child and its parent
                    {
                        return _links[1].SourceId;
                    }
                    else
                    {
                        return 0;
                    }/*delay-heavy processing*/
                });
                //Any independent processing
                int result = await processing;
                //Processing dependent on the result
                return result;
            }

            public async Task <int> Fidname(object _id)
            {
                Task<int> processing = Task.Run(() => {
                    string _wiql =

    String.Format("SELECT [System.Id],[System.Title],[System.Links.LinkType] FROM WorkItemLinks WHERE ([Source].[System.Id] = {0})" +
    " And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Reverse')" +
    " And ([Target].[System.WorkItemType] = 'Feature') ORDER BY [System.Id]", _id);


    Microsoft.TeamFoundation.WorkItemTracking.Client.Query _query = new Microsoft.TeamFoundation.WorkItemTracking.Client.Query(_workitemstore, _wiql);

                    WorkItemLinkInfo[] _links = _query.RunLinkQuery();
                    if (_links.Count() == 2) //only 1 child and its parent
                    {
                        return _links[1].TargetId;
                    }
                    else
                    {
                        return 0;
                    }/*delay-heavy processing*/
                });
                //Any independent processing
                int result = await processing;
                //Processing dependent on the result
                return result;

    }

            public async Task<string> fname(object fid)
            {
                Task<string> processing = Task.Run(() => {
                    string Ftitle = "";
                    string _wiql = string.Format("SELECT[System.Title], [System.Id]" +
                        " FROM WorkItems WHERE[System.Id]  = {0}" +
                        "  AND[System.WorkItemType] = 'Feature' ORDER BY[Microsoft.VSTS.Common.Priority]", fid);
                    Microsoft.TeamFoundation.WorkItemTracking.Client.Query _query = new Microsoft.TeamFoundation.WorkItemTracking.Client.Query(_workitemstore, _wiql);
                    WorkItemCollection workItemCollection = _query.RunQuery();

                    foreach (WorkItem workItem in workItemCollection)
                    {
                        Ftitle = workItem.Title;
                    }

                    return Ftitle; /*delay-heavy processing*/
                });
                //Any independent processing
                string result = await processing;
                //Processing dependent on the result
                return result;
            }

Цитата:
функция fidname выдает ошибку, а _id пуст, пожалуйста, скажите мне, что нужно сделать, чтобы исправить эту ошибку.

Patrice T

Что делают эти 3 функции?

Akhil Jain

wiql есть во всех них, возвращающих int/string

Patrice T

Какую работу они выполняют?
целочисленная факторизация? шифр? хеширование? ...

Akhil Jain

wiql query tfs workitem проверка родителя или нет

1 Ответов

Рейтинг:
0

Jon McKee

var results = from myRow in dtTaskandBugs.AsParallel()
              select myRow;
results.ForAll(r =>
  {
    r["Storyid"] = GetStoryid(r["Id"]);
    r["FeatureID"] = Fidname(r["Storyid"]);
    r["FeatureName"] = r["FeatureID"].ToString() == "0" ? 
      "Anonymous" : 
      fname(r["FeatureID"]);
  });

PLINQ может помочь, если производительность является проблемой. Он фактически определяет, ожидает ли он ускорения, выполняя запрос параллельно, и будет работать параллельно или последовательно соответственно.

Если у вас есть контроль над GetStoryid(), Fidname(), или fname() функции, которые вы могли бы использовать async/await Если у них есть большая задержка (например, доступ к другой БД или что-то еще), это может помочь:
public async Task<int> GetStoryid(int id)
{
  Task<int> processing = Task.Run(() => { /*delay-heavy processing*/});
  //Any independent processing
  int result = await processing;
  //Processing dependent on the result
  return result;
}
//Same basic idea for Fidname() and fname()

var results = from myRow in dtTaskandBugs.AsParallel()
              select myRow;
results.ForAll(async r =>
  {
    Task<int> storyProcessing = GetStoryid(r["Id"]);
    Task<int> fidProcessing = Fidname(r["Storyid"]);
    Task<string> featureProcessing = r["FeatureID"].ToString() == "0" ? 
      Task.FromResult("Anonymous") : 
      fname(r["FeatureID"]);
    r["Storyid"] = await storyProcessing;
    r["FeatureID"] = await fidProcessing;
    r["FeatureName"] = await featureProcessing;
  });


Правка: исходная правка удалена из-за пробела.
EDIT2: Итак, после прочтения более подробно Query и видя ниже, что PLINQ не помогает, я предполагаю, что вызовы БД-это ваша самая большая проблема. Приведенный ниже код демонстрирует рабочий пример того, каким будет мое предложение (async) вместе с комментариями, которые помогут вам заставить его работать:
class Program
{
    private static Random randomNumber = new Random();

    static void Main(string[] args)
    {
        int tableRows = 10;
        List<Dictionary<string, int>> table = new List<Dictionary<string, int>>();
        for (int i = 0; i < tableRows; i++)
        {
            Dictionary<string, int> row = new Dictionary<string, int>();
            row.Add("Id", i);
            row.Add("StoryId", tableRows + i);
            row.Add("FeatureId", tableRows * 2 + i);
            table.Add(row);
        }

        var results = from myRow in table
                      select myRow;
        List<Task> tasks = new List<Task>();
        foreach (var result in results)
            tasks.Add(Process(result));
        Task.WaitAll(tasks.ToArray()); //this is a blocking operation to wait on
                                       //all tasks to complete
        Console.ReadKey();
    }

    public static async Task Process(Dictionary<string, int> row)
    {
        Task<int> storyProcessing = GetStoryid(row["StoryId"]);
        Task<int> fidProcessing = Fidname(row["FeatureId"]);
        Task<string> nameProcessing = fname(row["Id"]);
        await Task.WhenAll(storyProcessing, fidProcessing, nameProcessing);
        //---------
        Console.WriteLine($"#{row["Id"]} complete. SID: {storyProcessing.Result}, FID: {fidProcessing.Result}, FN: {nameProcessing.Result}");
        /*---------
         * Replace above with something like:
         * row["StoryId"] = storyProcessing.Result;
         * row["FeatureId"] = fidProcessing.Result;
         * row["Id"] = nameProcessing.Result;
         */
    }

    public static async Task<int> GetStoryid(int id)
    {
        //---------
        await Task.Delay(randomNumber.Next(10000));
        return id * 10;
        /*---------
         * Replace above with something like:
         * string _wiql = String.Format("SELECT [System.Id],[System.Title] " +
                           "FROM WorkItemLinks WHERE ([Source].[System.WorkItemType] = 'Product Backlog Item') " +
                           "And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') And ([Target].[System.Id] = {0}  " +
                           "AND  [Target].[System.WorkItemType] = 'Task')" +
                           " ORDER BY [System.Id] mode(Recursive,ReturnMatchingChildren)", _TbId);
         * Query _query = new Query(_workitemstore, _wiql);
         * WorkItemLinkInfo[] links = await Task.Factory.FromAsync(_query.BeginLinkQuery, _query.EndLinkQuery);
         * if (links.Count() == 2)
         *     return links[1].SourceId;
         * return 0;
         */
    }
    public static async Task<int> Fidname(int id)
    {
        //---------
        await Task.Delay(randomNumber.Next(10000));
        return id * 10;
        /*---------
         * Replace above with something like:
         * string _wiql = String.Format("SELECT [System.Id],[System.Title],[System.Links.LinkType] FROM WorkItemLinks WHERE ([Source].[System.Id] = {0})" +
                          " And ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Reverse')" +
                          " And ([Target].[System.WorkItemType] = 'Feature') ORDER BY [System.Id]", _id);
         * Query _query = new Query(_workitemstore, _wiql);
         * WorkItemLinkInfo[] links = await Task.Factory.FromAsync(_query.BeginLinkQuery, _query.EndLinkQuery);
         * if (links.Count() == 2)
         *     return links[1].TargetId;
         * return 0;
         */
    }
    public static async Task<string> fname(int id)
    {
        await Task.Delay(randomNumber.Next(10000));
        return $"{id * 10}";
        /*---------
         * Replace above with something like:
         * string Ftitle = "";
         * string _wiql = string.Format("SELECT[System.Title], [System.Id]" +
                              " FROM WorkItems WHERE[System.Id]  = {0}" +
                              "  AND[System.WorkItemType] = 'Feature' ORDERBY[Microsoft.VSTS.Common.Priority]", fid);
         * Query _query = new Query(_workitemstore, _wiql);
         * WorkItemCollection workItems = await Task.Factory.FromAsync(_query.BeginQuery, _query.EndQuery);
         * foreach (WorkItem workItem in workItems)
         *     Ftitle = workItem.Title;
         * return Ftitle;
         */
    }
}

Дополнительная информация: Асинхронное программирование на основе задач (TAP)[^], АПМ нажать[^], и Запрос[^].


Akhil Jain

получение функции fidname вызывает ошибку, а _id пуст, пожалуйста, скажите мне, что нужно сделать, чтобы исправить эту ошибку. обновил свой код в пробной части.

Jon McKee

Какую ошибку вы видите? Если _id пусто в начале функции, которую я бы проверил, чтобы убедиться r["Storyid"] существует. Я бы также попытался посмотреть, можете ли вы пакетно выполнять запросы для каждой строки. Каждый выбор строки запускает 3 отдельных запроса к БД-это не совсем хорошая идея, если речь идет о производительности.

Akhil Jain

_id в fidname не получает значения и из-за которого запрос в string.format в этой функции (fidname) не получает значения и выбрасывает ошибку.очень хорошо, но медленно (17 мин), если я удалю код u предложил мне этот ответ.

Jon McKee

Является ли ошибка исходящей от Query и если да, то какая часть - вызов конструктора или выполнение запроса? Если нет, то так ли это String.Format? Если да, то не могли бы вы поставить точку останова раньше Task.Run и дальше string _wiql. Проверьте значение _id Если это нормально на первой точке останова, но не на второй, попробуйте переместить string _wiql определение до начала функции, а не внутри нее. Task.Run Отладка невероятно сложна без трассировки стека, полного соответствующего кода и знания конкретных используемых библиотек, таких как Microsoft.TeamFoundation.WorkItemTracking.Client. У меня действительно есть новое предложение наверху, хотя после прочтения о Query для последующей отладки.

Akhil Jain

Выполнение запроса, так как он не получает _id.

Jon McKee

Я не могу реально помочь, если не знаю объективно, что это так. Говорит ли об этом исключение? Разместите соответствующую информацию о точке останова для _id, предпочтительно трассировка стека/исключение, и укажите, на какую строку кода указывает трассировка, так как я не вижу ваших номеров строк. Хотя, скорее всего, я не смогу отладить асинхронную проблему через чат. Вы пробовали просто использовать PLINQ (первый пример в моем посте) без асинхронного программирования сверху? Это должно помочь само по себе, если у вас есть большое количество строк.

Akhil Jain

PLINQ не помог пробовал никакого улучшения производительности..

Jon McKee

Я добавил чисто async предложение в моем первоначальном решении. Если PLINQ не помогает не нужно усложнять код с его помощью :)

BillWoodruff

+5 впечатляющий отклик

BillWoodruff

Я думаю, что Джон ведет тебя по правильному пути. Это на вас, чтобы сделать основные исследования и эксперименты, необходимые для использования сложных функций PLinq.

Maciej Los

5ed!