如何优化统计计数序列及其工作原理如此缓慢

时间:2011-05-11 13:12:14

标签: linq-to-sql optimization f# sequence

简介:我花了一整天的时间来研究为什么我的处理操作如此之慢。低数据真的很慢。我检查了sql视图,程序和linq逻辑 - 所有这些都很完美。但后来我发现这个小东西需要很长时间来处理。

member X.CountStatistics()= 
    linq.TrueIncidents
    |> PSeq.groupBy (fun v -> v.Name)
    |> PSeq.map (fun (k, vs) -> k, PSeq.length vs)
    |> Array.ofSeq

它只是计算分组值,但花费了多少时间!简易桌上约10秒钟,

必须有一些生气的递归,但我看不到它......

如何让这项操作“快一点”或将其重新编码为linq-to-sql?

3 个答案:

答案 0 :(得分:4)

如果我理解正确,TrueIncidents是数据库中的一个表,您将整个内容拉入客户端应用程序以进行一些分组和计数。如果TrueIncidents是一个大表,那么这个操作总是会变慢,因为你正在移动大量的数据。执行此操作的“正确”方法是在数据库上,因为建议使用linq to SQL,或者Tomas建议使用存储过程。

关于PSeq,我不认为内联会产生很大的影响。并行化有一个开销,为了分摊这个开销,列表需要相对较大,并且您对列表中每个项目执行的操作需要很大。如果您对每个项目执行的操作非常昂贵,那么并行化可能对于小列表是值得的,但是相反的情况似乎是正确的;即使列表非常大并行化一个小的操作也不值得开销。因此,在这种情况下的问题是您对列表中的每个项目执行的操作太小,因此并行化的成本将始终使操作变慢。为了看到这一点,考虑下面的C#程序我们在一个包含1000万个项目的列表上执行一个简单的添加,你会发现并行版本总是运行缓慢(好吧,在我正在处理的机器上,这个两个内核,我想在具有更多内核的机器上,结果可能会有所不同)。

    static void Main(string[] args)
    {
        var list = new List<int>();
        for (int i = 0; i < 10000000; i++)
        {
            list.Add(i);
        }

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var res1 = list.Select(x => x + 1);
        foreach (var i in res1)
        {

        }
        stopwatch.Stop();
        Console.WriteLine(stopwatch.Elapsed);
        // 00:00:00.1950918 sec on my machine

        stopwatch.Start();
        var res2 = list.Select(x => x + 1).AsParallel();
        foreach (var i in res2)
        {

        }
        stopwatch.Stop();
        Console.WriteLine(stopwatch.Elapsed);
        // 00:00:00.3748103 sec on my machine
    }

答案 1 :(得分:3)

当前版本的F#LINQ支持有点限制。

我认为写这个的最好方法是牺牲一些使用F#的优雅,并将其作为SQL中的存储过程编写。然后,您可以将存储过程添加到linq数据上下文中,并使用生成的方法很好地调用它。当F#LINQ将来有所改进时,你可以改回来: - )。

关于PSeq示例 - 据我所知,存在一些效率问题,因为这些方法没有内联(由于内联,编译器能够进行一些额外的优化,并且它消除了一些开销)。您可以尝试下载源代码并将inline添加到mapgroupBy

答案 2 :(得分:0)

正如在其他答案中已经提到的那样,如果从数据库中提取大量数据然后对这个大型数据集进行一些计算,那么这将是非常昂贵的(我认为IO部分将比计算部分更昂贵)。在您的特定情况下,您似乎想要计算每个事件名称。一种方法是使用F#linq-sql只从数据库中引入事件的“名称”(没有其他列,因为你不需要它们),然后在F#中进行分组和映射操作。它可以帮助您提高性能,但不确定改进程度。