如何优化此操作以获得更好的性能?我需要把一个计时器放在什么时候从网址等"获取"XML数据

Obs*_*vus 5 c# asp.net asp.net-mvc performance actionresult

我有一个我觉得非常沉重的动作结果,所以我想知道如何优化它以便它获得更好的性能.此Web应用程序将同时由+ 100,000个用户使用.

现在我的Actionresult做了以下事情:

  • 从Internet URL检索XML文件
  • 将xml数据填充到我的数据库
  • 数据库数据填充了我的Viewmodel
  • 将模型返回到视图

每次用户访问视图时,此4个函数都会触发.这就是为什么我认为这个Actionresult非常糟糕.

如何将以下内容添加到我的Actionresults中?

添加计时器来检索XML文件并将xml数据填充到DB,就像每10分钟一样,因此每次用户访问视图时都不会触发.每次用户访问站点时,唯一需要触发的功能是viewmodel绑定并返回模型.我怎么能做到这一点?

注意:

  • xml文件每10分钟左右更新一次新数据.
  • 我有大约50个动作结果,它们执行相同的获取xml数据并添加到数据库但有50个不同的xml文件.
  • 如果xml URL处于脱机状态,则应跳过整个xml检索和数据库添加,然后执行模型绑定

这是我的行动结果:

public ActionResult Index()
        {
            //Get data from xml url (This is the code that shuld not run everytime a user visits the view)
            var url = "http://www.interneturl.com/file.xml";
            XNamespace dcM = "http://search.yahoo.com/mrss/";
            var xdoc = XDocument.Load(url);
            var items = xdoc.Descendants("item")
            .Select(item => new
            {
                Title = item.Element("title").Value,
                Description = item.Element("description").Value,
                Link = item.Element("link").Value,
                PubDate = item.Element("pubDate").Value, 
                MyImage = (string)item.Elements(dcM + "thumbnail")
               .Where(i => i.Attribute("width").Value == "144" && i.Attribute("height").Value == "81")
               .Select(i => i.Attribute("url").Value)
               .SingleOrDefault()
            })
            .ToList();

            //Fill my db entities with the xml data(This is the code that shuld not run everytime a user visits the view)
            foreach (var item in items)
            {
                var date = DateTime.Parse(item.PubDate);
                if (!item.Title.Contains(":") && !(date <= DateTime.Now.AddDays(-1)))
                    {
                        News NewsItem = new News();
                        Category Category = new Category();
                        var CategoryID = 2;

                        var WorldCategoryID = re.GetByCategoryID(CategoryID);
                        NewsItem.Category = WorldCategoryID;

                        NewsItem.Description = item.Description;
                        NewsItem.Title = item.Title.Replace("'", "");
                        NewsItem.Image = item.MyImage;

                        NewsItem.Link = item.Link;
                        NewsItem.Date = DateTime.Parse(item.PubDate);
                        re.AddNews(NewsItem);
                        re.save();
                    }
                }


            //All code below this commenting needs to run everytime a user visits the view
            var GetAllItems = re.GetAllWorldNewsByID();

            foreach (var newsitemz in GetAllItems)
            {
                if (newsitemz.Date <= DateTime.Now.AddDays(-1))
                {
                    re.DeleteNews(newsitemz);
                    re.save();
                }

            }

            var model = new ItemViewModel()
            {
               NewsList = new List<NewsViewModel>()
            };

            foreach (var NewsItems in GetAllItems)
            {
                FillProductToModel(model, NewsItems);
            }

            return View(model);
        }
Run Code Online (Sandbox Code Playgroud)

现在,每当用户访问索引视图时,它将获取XML数据并将其添加到数据库中,因此我在存储库中执行的错误修复正在关注addNews:

 public void AddNews(News news)
        {
            var exists = db.News.Any(x => x.Title == news.Title);

             if (exists == false)
            {
                db.News.AddObject(news);
            }
            else
            {
                db.News.DeleteObject(news);
            }
        }
Run Code Online (Sandbox Code Playgroud)

任何类型的解决方案和信息都非常感谢!

Kei*_*ith 3

这里可以做很多事情:文件是否必须是 XML(与 JSON 相比非常冗长)?每次都必须保存到DB吗?

但是,假设您必须执行每一步,那么您有两个瓶颈:

  1. 等待 XML 文件下载/解析
  2. 将所有 XML 数据保存到 DB

有几种方法可以加快速度:

设置轮询间隔

如果您很高兴没有立即看到更新,那么您可以执行以下操作:

  • 检查数据库的最新更新。
  • 如果(且仅当)最后一次更新时间超过 10 分钟:
    • 从 Internet url 检索 XML 文件
    • 将 xml 数据填充到我的数据库中
  • 数据库数据填充我的视图模型
  • 将模型返回到视图

这意味着您的数据最多可能会过时 10 分钟,但绝大多数请求只需填充模型即可。

根据您使用它的方式,您可以使这变得更加简单 - 只需添加一个OutputCache属性:

[OutputCache(Duration=600)]
public ActionResult Index() { ...
Run Code Online (Sandbox Code Playgroud)

这将告诉浏览器仅每 10 分钟刷新一次。您还可以设置该Location属性,使其仅由浏览器缓存或在服务器上为每个人缓存。

使 XML 检索异步

在下载 XML 文件期间,您的代码基本上只是等待 URL 加载 - 使用asyncC# 中的 new 关键字,您不需要在这里等待。

public async Task<ActionResult> Index()
{
    // Get data from xml url
    string url = "http://www.interneturl.com/file.xml";
    XNamespace dcM = "http://search.yahoo.com/mrss/";

    // The await keyword tells the C# code to continue until the slow action completes
    var xdoc = await LoadRemoteXmlAsync(url, dcM);

    // This won't fire until LoadRemoteXmlAsync has finished
    var items = xdoc.Descendants("item")
Run Code Online (Sandbox Code Playgroud)

使用的内容比我在这里所能涵盖的要多得多async,但如果您使用的是最新的 C# 和 MVC,那么开始使用它可能会相当简单。

仅进行 1 次 DB 调用

您当前的数据库保存操作非常次优:

  • 您的代码遇到了通常称为N+1 问题的问题
  • 每次添加时,您首先要检查标题并删除记录。这是一种非常缓慢的更新方式,并且将使得使用任何索引来优化它变得非常困难。
  • 你每次都会循环浏览所有的新闻文章,并把旧的都一一删除。这比单个delete from News where ...查询慢得多。

基于此,我将尝试以下更改(按照它们应该有多简单的粗略顺序):

  1. 更改您的AddNews方法 - 如果新数据不是较新的,则不要保存该项目的任何更改。

  2. 将删除循环更改为单个delete from News where Date <= @yesterday

  3. 查看新闻项标题和日期的索引,这些似乎是您查询最多的字段。

  4. 看看AddNews用执行upsert/ 的方法替换您的方法merge

  5. re.GetByCategoryID影响你的数据库吗?如果是这样,请考虑将其拆分出来,并将其构建到更新查询中或填充字典以更快地查找它。

基本上,对于每篇新新闻文章,您应该(至多)执行 1 次数据库操作,并执行 1 次删除旧新闻文章的数据库操作。目前,每篇文章有 3 个不到一天的文章 ( ++ re.GetByCategoryID) 、另外 1 个 ( ),然后每篇文章还有 1 个要删除 ( )。db.News.Anydb.News.Add|DeleteObjectre.GetAllWorldNewsByIDre.DeleteNews

添加分析

您可以向 MVC 项目添加分析,该项目将准确地告诉您每个步骤花费的时间,并帮助找到如何使用MiniProfiler对其进行优化。它在 StackOverflow 上使用,我自己也经常使用它 - 它会告诉你哪些步骤会减慢你的速度,哪些步骤不值得进行微观优化。

如果您不想使用 Visual Studio 中的优化工具以及RedGate ANTS等第三方工具。