【问题标题】:Is there a way to reduce the number of hits on the db有没有办法减少数据库的点击次数
【发布时间】:2014-02-07 15:14:58
【问题描述】:

我是 C#、ASP.NET MVC 和 SQL Server 的新手,但我已经让这段代码工作了

DateTime startDate = DateTime.Parse(start);
DateTime endDate = DateTime.Parse(end);

ViewData["TotalDuringPeriod"] = db.AlcoholForms.Count(x => x.CreatedDate >= startDate && x.CreatedDate <= endDate);
ViewData["TotalUniqueClientsDuringPeriod"] = db.AlcoholForms.Where(x => x.CreatedDate >= startDate && x.CreatedDate <= endDate).Select(x => x.ClientId).Distinct().Count();
ViewData["TotalGateNew"] = db.AlcoholForms.Count(x => x.ReferredTo == "Gate" && x.Reengagement == false && (x.CreatedDate >= startDate && x.CreatedDate <= endDate));
ViewData["TotalGateReengagment"] = db.AlcoholForms.Count(x => x.ReferredTo == "Gate" && x.Reengagement && (x.CreatedDate >= startDate && x.CreatedDate <= endDate));
ViewData["TotalSwitchNew"] = db.AlcoholForms.Count(x => x.ReferredTo == "Switch" && x.Reengagement == false && (x.CreatedDate >= startDate && x.CreatedDate <= endDate));
ViewData["TotalSwitchReengagement"] = db.AlcoholForms.Count(x => x.ReferredTo == "Switch" && x.Reengagement && (x.CreatedDate >= startDate && x.CreatedDate <= endDate));

List<ReportAlcoholReferals> reportData = db.AlcoholForms.Where(x => x.Referral && (x.CreatedDate >= startDate && x.CreatedDate <= endDate)).Select(x => new ReportAlcoholReferals()
            {
                FirstName = x.Client.FirstName,
                LastName = x.Client.LastName,
                Date = x.CreatedDate,                 
                ClientId = x.ClientId,
                AlcoholForm = x
            }).OrderBy(x => x.AlcoholForm.ReferredTo).ToList();
            return View(reportData);

现在它可以工作了,但我要访问数据库 7 次?有没有更好的方法来做到这一点? 有多大的性能问题

【问题讨论】:

  • 听起来您需要一个 List,这样您就可以查询一次,然后在所有后续 LINQ 查询中利用该对象。

标签: sql-server database-administration c# linq


【解决方案1】:

这就是我将如何处理这个问题,只是在不经常访问数据库的情况下。您可能还可以进行其他改进,但这不是您想要的。

DateTime startDate = DateTime.Parse(start);
DateTime endDate = DateTime.Parse(end);
List<AlcoholForms> formsList = db.AlcoholForms.Where(x => x.CreatedDate >= startDate && x.CreatedDate <= endDate).ToList();

ViewData["TotalDuringPeriod"] = formsList.Count();
ViewData["TotalUniqueClientsDuringPeriod"] = formsList.Select(x => x.ClientId).Distinct().Count();
ViewData["TotalGateNew"] = formsList.Count(x => x.ReferredTo == "Gate" && x.Reengagement == false);
ViewData["TotalGateReengagment"] = formsList.Count(x => x.ReferredTo == "Gate" && x.Reengagement);
ViewData["TotalSwitchNew"] = formsList.Count(x => x.ReferredTo == "Switch" && x.Reengagement == false);
ViewData["TotalSwitchReengagement"] = formsList.Count(x => x.ReferredTo == "Switch" && x.Reengagement);
List<ReportAlcoholReferals> reportData = formsList.Where(x => x.Referral).Select(x => new ReportAlcoholReferals()
{
    FirstName = x.Client.FirstName,
    LastName = x.Client.LastName,
    Date = x.CreatedDate,                 
    ClientId = x.ClientId,
    AlcoholForm = x
}).OrderBy(x => x.AlcoholForm.ReferredTo).ToList();

return View(reportData);

formsList 的列表声明意味着数据库将被查询一次并将结果存储在 List 对象中。从那里,您可以继续使用 LINQ 来分解您的数据。

【讨论】:

  • 出于好奇——这真的能提高性能吗?一个包含七个项目的列表与七个字符串相比,大小仍然相等吗?
  • 这是你需要测试的东西。这有可能获胜,主要是因为减少了到数据库的往返次数。但是,您现在正在从数据库中提取所有内容,而不是经过大量过滤的极少量数据。这是否最终成为“胜利”取决于许多因素,例如数据库与应用程序的距离、实际过滤了多少数据、有多少数据没有 过滤等。例如,如果只有 1% 的记录在日期范围内,这可能是性能的净损失。
  • @theGreenCabbage 性能问题与字符串或其大小无关。
  • 您能否向我解释一下Liststring 对性能的影响/改进?
【解决方案2】:

您的第三个到第六个查询可以从四个不同的计数转换为一个分组来捕获每个组的计数:

var lookup = db.AlcoholForms.Where(x => x.CreatedDate >= startDate && 
        x.CreatedDate <= endDate)
    .GroupBy(x => new { x.ReferredTo, x.Reengagement },
        (key, items) => new{key, count = items.Count()})
    .ToDictionary(group => group.key, group => group.count);

ViewData["TotalGateNew"] = lookup[
    new { ReferredTo = "Gate", Reengagement = false }];
ViewData["TotalGateReengagment"] = lookup[
    new { ReferredTo = "Gate", Reengagement = true }];
ViewData["TotalSwitchNew"] = lookup[
    new { ReferredTo = "Switch", Reengagement = false }];
ViewData["TotalSwitchReengagement"] = lookup[
    new { ReferredTo = "Switch", Reengagement = true }];

【讨论】:

    【解决方案3】:

    往返次数不一定是坏事。你有没有分析过这七首热门歌曲,看看它们是否真的花时间?我的猜测是他们不是,这意味着你没事(除非这将在一个非常高容量的站点上运行)。

    另一种方法是编写一个 T-SQL 存储过程,一次性返回您需要的所有值。然后,您可以将结果捕获为一个对象,或者只是一个整数列表,或其他任何内容。

    【讨论】:

    • 一个存储过程仍然会多次查询数据库。
    • @Ellesedil 但它可以写得更有效(想想Servy的答案,但在T-SQL中),如果我正确理解问题,还可以减少往返次数。
    • @Ellesedil 关键是您减少了应用程序和数据库之间的网络流量。 OP 代码的问题不在于 DB 实际为每个结果生成响应所花费的时间,而是从应用程序获取请求到 DB 以及从 DB 到应用程序的响应。 这样做会使流量减少约 7 倍。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    相关资源
    最近更新 更多