提高LINQ查询的性能

时间:2012-07-09 19:31:56

标签: c# asp.net xml linq

当我尝试循环结果以创建Xelement时,我的linq查询变慢,我稍后根据XElement处理XSLT。

这是我的代码

public override XElement Search(SearchCriteria searchCriteria)
    {
        XElement root = new XElement("Root");
        using (ReportOrderLogsDataContext dataContext = DataConnection.GetLinqDataConnection<ReportOrderLogsDataContext>(searchCriteria.GetConnectionString()))
        {
            try
            {


                IQueryable<vw_udisclosedDriverResponsePart> results = from a in dataContext.vw_udisclosedDriverResponseParts
                              where
                                  (a.CreateDt.HasValue &&
                                   a.CreateDt >= Convert.ToDateTime(searchCriteria.BeginDt) &&
                                   a.CreateDt <= Convert.ToDateTime(searchCriteria.EndDt))
                              select a;

                if (!string.IsNullOrEmpty(searchCriteria.AgentNumber))
                {
                    results = results.Where(request => request.LgAgentNumber == searchCriteria.AgentNumber);
                }
                if (!string.IsNullOrEmpty(searchCriteria.AgentTitle))
                {
                    results = results.Where(a => a.LgTitle == searchCriteria.AgentTitle);
                }
                if (!string.IsNullOrEmpty(searchCriteria.QuotePolicyNumber))
                {
                    results = results.Where(a => a.QuotePolicyNumber == searchCriteria.QuotePolicyNumber);
                }
                if (!string.IsNullOrEmpty(searchCriteria.InsuredName))
                {
                    results = results.Where(a => a.LgInsuredName.Contains(searchCriteria.InsuredName));
                }

                foreach (var match in results) // goes slow here, specifically times out before evaluating the first match when results are too large.
                {
                    DateTime date;
                    string strDate = string.Empty;
                    if (DateTime.TryParse(match.CreateDt.ToString(), out date))
                    {
                        strDate = date.ToString("MM/dd/yyyy");
                    }

                    root.Add(new XElement("Record",
                                          new XElement("System", "Not Supported"),
                                          new XElement("Date", strDate),
                                          new XElement("Agent", match.LgAgentNumber),
                                          new XElement("UserId", match.LgUserId),
                                          new XElement("UserTitle", match.LgTitle),
                                          new XElement("QuoteNum", match.QuotePolicyNumber),
                                          new XElement("AddressLine1", match.AddressLine1),
                                          new XElement("AddressLine2", match.AddressLine2),
                                          new XElement("City", match.City),
                                          new XElement("State", match.State),
                                          new XElement("Zip", match.Zip),
                                          new XElement("DriverName", string.Concat(match.GivenName, " ", match.SurName)),
                                          new XElement("DriverLicense", match.LicenseNumber),
                                          new XElement("LicenseState", match.LicenseState)));
                    ;
                }
            }
            catch (Exception es)
            {

                throw es;
            }
        }
        return root;
        // return GetSearchedCriteriaFromStoredPocedure(searchCriteria);
    }

我假设有一种更好的方法将结果对象转换为XElement。处理视图本身只需要大约2秒钟。尝试遍历结果对象会导致超时,即使未返回许多结果也是如此。

任何帮助都将不胜感激。

谢谢!

-James

AMENDED 7/10/2012

问题不在于linq查询本身,而是在指定日期范围时执行视图。单独执行视图大约需要4-6秒。当使用较小的日期范围(07/05/2012 - 07/10/2012)时,视图大约需要1:30。有没有人有任何关于如何提高指定日期范围的查询性能的建议。如果我得到所有结果并通过它们检查日期,它会更快。

    IQueryable<vw_udisclosedDriverResponsePart> results = from a in dataContext.vw_udisclosedDriverResponseParts select a;

                foreach (var match in results) //results only takes 3 seconds to enumerate, before would timeout
                {
                    // eval search criteria date here.
                }

我可以像上面提到的那样编写代码,但有没有人有更好的方法?

3 个答案:

答案 0 :(得分:2)

数据库如何运作?最简单的测试是运行一个示例查询 - 一个将从数据库中检索所需数据的查询,只是为了测试数据库索引和性能 - 因为在99%的情况下这是导致速度缓慢的原因。

我猜想发生缓慢是因为

  • 您正在从数据库进行迭代,而不是预先检索所有行,并且
  • 您选择了不良WHERE条件(您的索引是否正确?)

首先,调用ToList来获取结果以确定数据库中发生的缓慢,而不是XML结构

if (!string.IsNullOrEmpty(searchCriteria.InsuredName))
{
    //...
}    
var matches = results.ToList();    
foreach (var match in matches) 
{
    //...

假设var matches = results.ToList()非常慢,我会查看WHERE子句中的函数

(a.CreateDt.HasValue &&
a.CreateDt >= Convert.ToDateTime(searchCriteria.BeginDt) &&
a.CreateDt <= Convert.ToDateTime(searchCriteria.EndDt))

检查它们是否每行都没有被执行。

如果使用SQL Server,请运行Profiler(在“工具”菜单中)以跟踪LINQ-to-SQL的SQL。

答案 1 :(得分:1)

当然,在linq之外进行转换。标准不会改变 在Linq表达式的运行时期间。

根据你发布的内容,我做了这个例子:

var begin = Convert.ToDateTime(searchCriteria.BeginDt);
var end = Convert.ToDateTime(searchCriteria.EndDt);

var results = from a in searchList
              where ((a.CreateDt.HasValue &&
                      a.CreateDt >= begin &&
                      a.CreateDt <= end)
                      && (string.IsNullOrEmpty(searchCriteria.AgentNumber) || a.LgAgentNumber == searchCriteria.AgentNumber)
                      && (string.IsNullOrEmpty(searchCriteria.AgentTitle) || a.LgTitle == searchCriteria.AgentTitle)
                      && (string.IsNullOrEmpty(searchCriteria.QuotePolicyNumber) || a.LgTitle == searchCriteria.QuotePolicyNumber)
                      && (string.IsNullOrEmpty(searchCriteria.InsuredName) || a.LgInsuredName.Contains(searchCriteria.InsuredName))
                     )
                        select a;

也许这对你有帮助。

为了测量时间,我使用了以下内容:

var watch = new Stopwatch();
watch.Start();
var arr = results.ToArray();  // force evaluation of linq
watch.Stop();
var elapsed = watch.ElapsedTicks;

似乎更改后的查询平均速度已快30-40%,但我只是 做了一些运行。

答案 2 :(得分:1)

我建议做一些实验:

一。
放一个

int count = results.Count();
foreach 之前

,看看这是否需要很长时间。

两个。
保留 Count()调用,看看 foreach 是否仍然很慢。如果速度很快,则表明与db的初始连接速度很慢。

正如其他人所建议的那样 - 看看你如何在db中查询(实际上是在数据库中输入,没有c#)。

您还可以发布SHOW TABLE结果,以便社区可以检查索引并帮助您修复。