【问题标题】:Optimize linq query for performance(now takes 12-15seconds, need 3seconds) [closed]优化 linq 查询的性能(现在需要 12-15 秒,需要 3 秒)[关闭]
【发布时间】:2012-12-16 07:20:21
【问题描述】:

编辑:我需要帮助将这些 linq 查询重写为 SQL 查询以获得尽可能高的性能。

我有一个大约有 1000 万行的表。它由 7 列组成,包括 Id。首先是 Id,然后是“TradeObjectModel”的三个键,最后是保持不同 TradeObjectModels 评级值的三个整数。像这样:

当用户,例如 To1Id(TradeObjectModel1 所有者),使用键 71 处理她对其他 Trade 对象的评级时,只有一行足以用于当前视图。

我解决这个问题的尝试看起来像这样(代码示例下面的解释):

IEnumerable<RatingListTriangleModel> allTriangleModels1 =
                this._ratingListTriangleRepository.All.Where(
                    ratingListRow =>
                    ratingListRow.To1Id == myTradeObject.TradeObjectId);
            var filteredallTriangleModels1 = from row in allTriangleModels1
                                             group row by row.To2Id into g
                                             select g.First();


            IEnumerable<RatingListTriangleModel> allTriangleModels2 =
                this._ratingListTriangleRepository.All.Where(
                    ratingListRow =>
                   ratingListRow.To2Id == myTradeObject.TradeObjectId);
            var filteredallTriangleModels2 = from row in allTriangleModels2
                                             group row by row.To3Id into g
                                             select g.First().

            IEnumerable<RatingListTriangleModel> allTriangleModels3 =
                this._ratingListTriangleRepository.All.Where(
                    ratingListRow =>
                   ratingListRow.To3Id == myTradeObject.TradeObjectId);

            var filteredallTriangleModels3 = from row in allTriangleModels3
                                             group row by row.To1Id into g
                                             select g.First();


            var fileredallTriangleModels =
                filteredallTriangleModels1.Union(filteredallTriangleModels2).Union(filteredallTriangleModels3).ToList();


            ViewBag.TriangleCount = fileredallTriangleModels.Count();

            foreach (var ratingListRow in fileredallTriangleModels)
            {
                //Find which one is my ad and set me as setter and their object as receiver
                if (ratingListRow.To1Id == customer.TradeObjectId)
                {
                    var ri = new TriangleViewModel(
                        customer.TradeObjectId,
                        this._customerRepository.FindTradeObjectId(ratingListRow.To2Id),
                        ratingListRow,
                        this._tradeobjectRepository.Find(ratingListRow.To2Id));

                    model.Models3.Add(ri);
                    continue;
                }

                if (ratingListRow.To2Id == customer.TradeObjectId)
                {
                    var ri = new TriangleViewModel(
                        customer.TradeObjectId,
                        this._customerRepository.FindTradeObjectId(ratingListRow.To3Id),
                        ratingListRow,
                        this._tradeobjectRepository.Find(ratingListRow.To3Id));

                    model.Models3.Add(ri);
                    continue;
                }

                if (ratingListRow.To3Id == customer.TradeObjectId)
                {
                    var ri = new TriangleViewModel(
                        customer.TradeObjectId,
                        this._customerRepository.FindTradeObjectId(ratingListRow.To1Id),
                        ratingListRow,
                        this._tradeobjectRepository.Find(ratingListRow.To1Id));
                    model.Models3.Add(ri);
                }
            }

首先我得到我的对象在第一列的所有行,将它们分组以仅选择一个,然后在第二列和第三列继续对我做同样的事情。这里的 ToList() 只是临时的,让 med 能够在它们上运行秒表,每个都需要 0-12 秒。然后我加入它们并运行它们,以在前端代码中创建 webgrid 使用的模型。

这会导致两个问题: 1. 需要很长时间。和 2. 如果我的 tradeobject id 位于不止一列,我将得到不止一行,显示不止一个我感兴趣的 Tradeobject。

【问题讨论】:

  • 如果存储库来自远程源,一项优化是删除单个列表上的 .ToList() 调用,并将其应用到 union
  • @MagnusKarlsson 他们很可能影响你的表现。
  • Linq 隐藏了很多复杂性,但副作用是 Linq 也隐藏了幕后发生的事情。这对于简单查询来说是可以的,当您可以“感觉”发生了什么时,但是当查询变得复杂时,我认为编写一个经过优化的纯 SQL 查询要好得多,以便准确控制数据库层发生的事情。
  • @MagnusKarlsson 但是ToList() 是查询运行方式的重大变化。您可以不以这种方式比较性能。 ToList() 使您的查询提前实现。
  • 请发布执行计划。没有这个就不可能给出有用的答案。

标签: sql performance tsql linq-to-entities query-optimization


【解决方案1】:

尝试使用 Database Engine Tuning Advisor 来查看添加/删除/更改表上的索引是否显着提高了 LINQ 查询提供的工作负载的性能。

【讨论】:

  • 我无法从中获得任何有用的信息。花一点时间来学习它......
  • 除非你真的理解这些建议,否则请不要盲目相信DTA提供的“解决方案”。这可能会给您带来更多麻烦。
  • 非常正确——这是一个合理的起点。 @magnuskarlsson 说真的,坚持——或者另一种选择是拿起一本涵盖 SQL Server 索引的好书。
  • @tomfanning 我阅读了索引并使用 sql profiler 进行了工作负载,使用 DTA 运行它,根据结果我意识到我将不得不重写应用程序的工作流程并进行一些较小的更改,然后回到评估索引。感谢您抽出宝贵时间,因为您建议首先将索引作为性能增强器,我会将您的问题标记为正确答案,即使它引导我走向新的方向,而不是回答具体问题。 BR 马格努斯
【解决方案2】:

尝试使用分析器捕获您的查询,并隔离前 3 个运行时间最长的查询。将它们复制到 SSMS 中并执行它们。寻找实际的执行计划。查找表扫描或估计记录数与实际记录数之间的巨大差异。从这里开始,要么统计信息关闭,要么您可以考虑放置一个索引来覆盖查询。

【讨论】:

  • 另外,您可能会考虑发布您的 XML 版本的实际执行计划,以便我们为您提供更有针对性的解决方案提示。
  • 我一直在努力解决这个问题。会回复你的。谢谢!
【解决方案3】:

从性能的角度来看,使用某种存储过程可能会更好。 LINQ 往往会通过这些类型的查询/查找来减慢速度。但是,如果存储过程还不够,您可以做一些事情。

首先,您可能想看看Incremental Search,它基本上是通过保持搜索继续进行或“延迟”执行给定时间而编写的。这应该适用于任何 IEnumerable。

我建议的下一件事是看看您是否可以潜在地集成类似于上面的增量搜索的东西(通过使用 Add 函数等),以便为适用于您的程序的任何东西进行类似的实现。

说真的 - 我在过去看到了存储过程的巨大改进,这肯定会提高速度(在我的例子中,一个查询减少了近 10 倍!)

【讨论】:

  • 对不起,不知道怎么写成sql程序。不过,我会看看 incemental search!
猜你喜欢
  • 2019-08-01
  • 2015-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
相关资源
最近更新 更多