【问题标题】:How do I optimize this Linq query to find blog posts with the most views in past 24 hours如何优化此 Linq 查询以查找过去 24 小时内查看次数最多的博客文章
【发布时间】:2014-10-24 15:35:53
【问题描述】:

我有一个博客网站,它定期从 Google Analytics 检索每篇博客文章的查看次数并将其存储在数据库中。 Blog 表与 ViewStats 表具有一对多的关系。 ViewStats 表简单存储日期和视图。

相关的2个表格如下:

|   Blog   |   ViewStats  |
-----------+--------------|
|   Id     |   Id         |
|   Title  |   Date       |
|   Body   |   Views      |
|          |   BlogId     |

这是一个使用实体框架的 MVC 网站,并在数据访问层中设置了存储库。

我想要做的是获得过去 24 小时内浏览次数最多的 3 篇博文。存储在数据库中的所有视图都是累积的,因此我需要按最近的结果减去 24 小时前的最后结果对每篇博文进行排序。

数据示例:

|   Id    |            Date              |   Views   |   BlogId   |    
----------+------------------------------+-----------+------------|
|    1    |   2014-10-01 16:05:37.573    |    10     |     1      |
|    2    |   2014-10-01 16:05:37.573    |     8     |     2      |
|    3    |   2014-10-01 16:10:40.333    |    32     |     1      |
|    4    |   2014-10-01 16:10:40.333    |    12     |     2      |

这是我的查询:

var query = blogRepo.GetBlogs()
    .OrderByDescending(a => 
        (a.ViewStats.OrderByDescending(v => v.Date)
            .Select(v => v.Views)
            .FirstOrDefault())
        - (a.ViewStats.Where(v => v.Date < DateTime.Now.AddDays(-1))
            .OrderByDescending(v => v.Date)
            .Select(v => v.Views)
            .FirstOrDefault()))
    .Take(3);

但是,现在 ViewStats 表中有大约 10,000 行,它的运行速度非常慢。有谁知道实现此结果的更有效方法?

谢谢。

【问题讨论】:

  • 不能在sql中完成任何(或全部)吗?
  • @Jerrington 如果 OP 使用的是 EF,那么 Linq 查询将被转换为 SQL。
  • 你考虑过做一个简单的 GROUP BY 吗?并检查您的索引。
  • 您可以通过更改 where 子句来加快这一速度,从而减少要排序的数据。 IE。在最近的位置上放置一个位置,以便它只获取数据库中过去 15 分钟内发生的记录。您还可以通过执行 where Date > Date - 1 day 之类的操作来交换 24 小时前的 where 和 order by,并进行升序排序而不是降序排序。
  • 确保您查询的是 IQueryable 而不是 IEnumerable。我专门看GetBlogs()

标签: c# linq asp.net-mvc-5 entity-framework-6


【解决方案1】:

根据您的 cmets,您的 blogRepo.GetBlogs() 返回一个 IEnumerable,它强制在内存中执行查询,而不是被转换为 SQL 并针对数据库运行。这就是为什么它很慢。

使GetBlogs() 返回IQueryable 以利用数据库速度。

【讨论】:

  • 谢谢。对 IQueryable 的更改是解决方案。但是,为了使存储库只返回 IEnumerable,我的高级开发人员建议将该方法放入存储库中的 GetPopularBlogs(int numOfResults) 中。非常感谢。
  • 很高兴,但您应该只需要一个,因为您可以使用 AsQueryableAsEnumerable 在两个界面之间来回切换。
【解决方案2】:

如果您在类中正确映射导航集合属性,则可以做到这一点。 还要确保您的 GetBlogs 方法返回 IQueryable。

// var blogs = blogRepo.GetBlogs();
var start = DateTime.Now.AddDays(-1);
var best =
    from blog in blogs
    let total = blog.Stats.Where(s => s.Date > start).Sum(i => i.Views)
    orderby total descending
    select new
    {
        blog, total
    };

var results = best.Take(3);

这里的工作示例: https://dotnetfiddle.net/9C0p8c

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    相关资源
    最近更新 更多