【问题标题】:what can i do to improve performance of this code我能做些什么来提高这段代码的性能
【发布时间】:2015-08-03 09:57:11
【问题描述】:

我有这段代码可以查看所有联系人并对发送给他们的每封电子邮件进行计数,如果他们没有打开/单击最后一个 X 数量,则将它们返回到列表中

目前代码运行大约需要 10 分钟,有什么可以改进的吗?

我知道我可以限制退回的金额,但这仍然很慢。

var contactList =
        (from c in db.Contacts
            where c.Accounts_CustomerID == Account.AccountID && !c.Deleted && !c.EmailOptOut
            select c).ToList();

    foreach (var person in contactList)
    {
        var SentEmails =
            (from c in db.Comms_Emails_EmailsSents where c.ContactID == person.ID select c).OrderBy(
                x => x.DateSent).Take(Last).ToList();

        if (SentEmails.Count == Last)
        {
            if (!Clicks)
            {
                if (SentEmails.Count(x => x.Opens == 0) == Last)
                {
                    ReturnContacts.Add(person);
                }
            }
            else
            {
                if (SentEmails.Count(x => x.Clicks == 0) == Last)
                {
                    ReturnContacts.Add(person);
                }
            }
        }
    }
    return ReturnContacts;

【问题讨论】:

  • 首先使用性能分析器(例如 dotTrace)来了解究竟是什么进展缓慢。
  • 你需要一个 Join 查询。

标签: c# linq


【解决方案1】:

删除 .ToList() 并使用 IQueryables。通过使用 iqueryables,代码将执行一次并减少内存。 ToList() 检索所有实体并将它们存储在您不想要的内存中。

【讨论】:

    【解决方案2】:

    在 db 上运行逻辑 - 使用连接等重写查询,使其返回已包含相关数据的结果集。

    您现在所做的是为每个初始查询结果执行一个数据库查询。这可能意味着很多查询。

    如果您将其卸载到 RDBMS,您可以随时尝试并在那里优化它(通过引入索引等)。

    编辑:我在记事本中重写了代码:

    foreach(var record in (from c in db.Contacts
    join es in db.Comms_Emails_EmailsSents
    on c.Id equals es.ContactId
    where c.Accounts_CustomerID == Account.AccountID && !c.Deleted && !c.EmailOptOut
    orderby c.Id, es.DateSent descending
    select new {opens=es.Opens, clicks=es.Clicks, person=c})
    .GroupBy(r=>r.person)){
        var mails = record.Take(Last).ToList();
        if(mails.Count == Last){
            if(!Clicks){
                if(mails.Count(x=>x.opens == 0) == Last){
                     ReturnContacts.Add(record.Key);
                }
            }
        }else
                {
                    if (SentEmails.Count(x => x.Clicks == 0) == Last)
                    {
                        ReturnContacts.Add(record.Key);
                    }
                }
    
    }
    

    我没有时间来模拟一个数据库并对其进行测试。此外,这种方法在联系人和电子邮件之间执行连接,如果您每人有 10 万封电子邮件,这可能是一个非常糟糕的主意。您可以使用 rank 函数对其进行优化,但我会说如果性能仍然很差,您可以开始考虑进行 db 端优化,因为这种数据结构 - 至少在我非 dba 的眼中 - 并不完美适合这种查询。

    【讨论】:

    • 用 sql 写这个最好的方法是什么?使用游标?
    • 完全不使用游标...如果可能的话 ;) 我会查看代码并尝试更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 2022-12-05
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 2014-09-06
    • 2020-07-20
    相关资源
    最近更新 更多