加速这个LINQ to SQL代码

时间:2011-04-01 14:45:24

标签: c# asp.net linq-to-sql

我正在开发一个ASP.NET,我需要在GridView中显示每个帐户的每次购买(所以基本上每个购买链接到一个帐户)。

问题是,我们有超过6000家供应商(授予,这些可以过滤到客户通常会做的大约1000个),每个供应商都会有一些交易。因此,您可以想象绑定此数据所需的时间非常长 - 实际上,SQL服务器偶尔会超时。遗憾的是,我无法使用分页,因为所有数据都需要在一个页面中显示。

我正在做的是类似于下面的代码(不在我的机器上,所以不能完全复制)

IEnumerable<Account> accs = (from s in dc.Accounts select s);
foreach (Account acc in accs)
{
    IEumerable<Purchases> purchs = (from s in dc.Purchases where s.AccountID == acc.ID select s);
    double 30daysval;
    double 60daysval;
    foreach (Purchases purch in Purchases)
    {
        TimeSpan span = DateTime.Now - purch.Timestamp;
        if (span.Days <= 30)
        {
            30daysval += purch.Value;
            //Add a row to the grid
        }
        else if (span.Days <= 60)
        {
            60daysval += purch.Value
            //Add a row to the grid
        }
    }
    //Add total row for that account
}

有没有更快的方法来做到这一点,也许在LINQ中使用join?我知道这可能有点无望,因为涉及的数据很大,而且在一个页面上显示几千行是相当荒谬的,但这就是我被告知要做的......

非常感谢任何想法或帮助

5 个答案:

答案 0 :(得分:2)

// Assuming that there is no fk keys.  Else you don't need joins.
var Purchases = dc.Accounts
    .Join(dc.Purchases, a => a.Id, p => p.AccountId, (a,p) => new {a,p})
    .Select(p);

double 30daysval;
double 60daysval;
foreach (Purchases purch in Purchases)
{
    TimeSpan span = DateTime.Now - purch.Timestamp;
    if (span.Days <= 30)
    {
        30daysval += purch.Value;
        //Add a row to the grid
    }
    else if (span.Days <= 60)
    {
        60daysval += purch.Value
        //Add a row to the grid
    }
}

答案 1 :(得分:1)

var resuts =                 (from acc in dc.Accounts
                             join purchase in dc.Purchases on 
                             acc.ID equals purchase.AccountID
                             select new {Account = acc, Purchase = purchase}).ToList();


daysVal30 = results.Where(x=>(DateTime.Now - x.Purchase.Timestamp).Days <= 30).Sum(x=>x.Purchase.Value);
daysVal60 = results.Where(x=>(DateTime.Now - x.Purchase.Timestamp).Days > 30 && (DateTime.Now - x.Purchase.Timestamp).Days <=60).Sum(x=>x.Purchase.Purchase.Value);

grid.DataSource = results;

答案 2 :(得分:1)

首先,您需要分析正在发送给数据库的SQL代码。

很有可能,对于您查询的每个帐户,都会向数据库发送一个新查询以加载您对该帐户的购买。这称为“延迟加载”或延迟加载。既然你总是需要它们,那就不是很有效了。

假设您拥有正确的外键,您可以使用LoadOptions确保只执行一个查询。

示例:

DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Account >(a => a.Purchases );
context.LoadOptions = options;

这样,所有购买都直接加载了帐户,这可能会节省大量时间。

答案 3 :(得分:0)

连接是主要的事情,但是额外的事情是有帮助的 - Linq to SQL(和Linq to Entities)不会将日期操作转换为SQL,但是它们能够将常量日期与值进行比较。

目前您正在寻找(现在 - 时间戳> 30天) - 我建议您重新安排并寻找(现在 - 30天&gt;时间戳)。您需要在C#中计算(现在 - 30天),因为表达式不会转换,但您可以在循环之前在数据库级别过滤行:

// Assuming that there is no fk keys.  Else you don't need joins.
var Purchases = dc.Accounts
    .Join(dc.Purchases, a => a.Id, p => p.AccountId, (a,p) => new {a,p})
    .Select(p); //this is not evaluated yet

var todayAnd30 = DateTime.Now.AddDays(30); //happens instantly in memory
var todayAnd60 = DateTime.Now.AddDaye(60); //happens instantly in memory

var purchases30 = Purchases.Where(p => p.Timestamp > todayAnd30); //will translate to SQL
var purchases60 = Purchases.Where(p => p.Timestamp > todayAnd60; //will translate to SQL

foreach (Purchases purch in purchases30) //purchases30 query hits database at this point
{
   30daysval += purch.Value;
   //any other processing
}

foreach (Purchases purch in purchases60) //purchases60 query hits database at this point
{
   60daysval += purch.Value;
   //any other processing
}

归功于Holystream,我将你的答案中的连接作为保存打字的起点!

答案 4 :(得分:0)

非常感谢所有回复的人,您的建议对我帮助很大。有一件事我忘了提到这是一个挑战,他们的用户可能想看到没有购买的帐户。

我最后做的是创建我自己的类,包含一个Account对象和一个Purchase对象列表。然后我在LINQ中进行外部联接以选择每个帐户及其购买,并将结果存储到这个新类中。