如何减少LINQ搜索查询的执行时间

时间:2016-04-14 05:24:47

标签: c# sql-server asp.net-mvc linq

我有一个查询有时返回几行但执行时间很长。我想知道为什么需要这么长时间,我该如何解决它。这是代码:

public IList<SearchUserResult> SearchLegacyUsers(string userName, string email, string firstName, string lastName, string city, int? stateID, 
        string postalCode, int? countryID)
    {
        using (var db = new MyModel.MyContext())
        {


            var users = (from pu in db.PersonUsernames
                         from pe in db.PersonEmails.Where(a => a.PersonID == pu.PersonID).DefaultIfEmpty()
                         from p in db.People.Where(b => b.UPID == pu.PersonID).DefaultIfEmpty()
                         from pa in db.Addresses.Where(c => c.PersonID == pu.PersonID).DefaultIfEmpty()
                         from sc in db.LU_State.Where(d => d.ID == pa.StateID).DefaultIfEmpty()
                         from pp in db.Phones.Where(e => e.UPID == pu.PersonID).DefaultIfEmpty()

                         select new SearchUserResult
                         {
                             PersonID = p.UPID,
                             UserName = pu.Username,
                             Email = pe.Email,
                             FirstName = p.FirstName,
                             MiddleName = p.MiddleName,
                             LastName = p.LastName,
                             Address = pa.Address1,
                             City = pa.City,
                             StateCode = sc.StateAbbr,
                             StateID = sc.ID,
                             PostalCode = pa.Zip,
                             Phone = pp.PhoneNumber,
                             CountryCode = sc.LU_Country.Name,
                             CountryID = sc.LU_Country.ID
                         }).ToList();

            if (!string.IsNullOrEmpty(userName)) users = users.Where(a => a.UserName.Contains(userName)).ToList();
            if (!string.IsNullOrEmpty(email)) users = users.Where(b => b.Email != null && b.Email.Contains(email)).ToList();
            if (!string.IsNullOrEmpty(firstName)) users = users.Where(c => c.FirstName.Contains(firstName)).ToList();
            if (!string.IsNullOrEmpty(lastName)) users = users.Where(d => d.LastName.Contains(lastName)).ToList();
            if (!string.IsNullOrEmpty(city)) users = users.Where(e => e.City.Contains(city)).ToList();
            if (stateID != null && stateID != 0)
            {
                users = users.Where(f => f.StateID == stateID).ToList();
            }
            if (!string.IsNullOrEmpty(postalCode)) users = users.Where(g => g.PostalCode.Contains(postalCode)).ToList();
            if (countryID != null && countryID != 0)
            {
                users = users.Where(h => h.CountryID == countryID).ToList();
            }

            return users;
        }

    }

任何改进的想法都非常受欢迎。

1 个答案:

答案 0 :(得分:0)

System.Linq命名空间有2个静态类,允许您使用LINQ查询和/或顺序(即Array,List,String)。这些类是Enumerable,其扩展方法适用于IEnumerable<T>类型。并Queryable处理IQueryable<>类型。

第一种类型的方法在内存中执行,第二种方法将代码转换为SQL并将其脚本发送到数据库。

IQueryable<T>类型继承自IEnumerable<T>,两者都在枚举时执行。默认情况下,数据库上下文中的所有序列都来自IQueryable<T>类型。

以下是如何通过枚举来执行查询的一些示例:

// these sentenses are all enumerated immediately
db.PersonUsernames.ToList();
db.PersonUsernames.Where(a => a.PersonID != 39).ToArray();
db.PersonUsernames.Count();
foreach(var person in db.PersonUsernames) { /* Do something */ }

// but, these are not 
string name = "";
var query = db.PersonUsernames.Where(a => a.PersonID != 39);
if (String.IsNullOrEmpty(name))
   query = query.Where(a => a.UserName == name);
query = query.OrderBy(q => q.PersonID);

// and when you want to enumerate it
// you just have to call ToList or enumerate it using foreach
query.ToList();
query.ToArray();
foreach(var q in query) { /* Do something */ }

所以你的代码看起来像这样:

public IList<SearchUserResult> SearchLegacyUsers(string userName, string email, string firstName, string lastName, string city, int? stateID, 
    string postalCode, int? countryID)
{
    using (var db = new MyModel.MyContext())
    {
        var users = (from pu in db.PersonUsernames
                     from pe in db.PersonEmails
                                  .Where(a => a.PersonID == pu.PersonID)
                                  .DefaultIfEmpty()
                     from p in db.People
                                 .Where(b => b.UPID == pu.PersonID)
                                 .DefaultIfEmpty()
                     from pa in db.Addresses
                                  .Where(c => c.PersonID == pu.PersonID)
                                  .DefaultIfEmpty()
                     from sc in db.LU_State
                                  .Where(d => d.ID == pa.StateID)
                                  .DefaultIfEmpty()
                     from pp in db.Phones
                                  .Where(e => e.UPID == pu.PersonID)
                                  .DefaultIfEmpty()
                     // when you use DefaultIfEmpty, you're saying that 
                     // if this sequence does not contain any item
                     // it'll return a sequense with just 1 null item.
                     // So, you have to verify if pe, p, pa, sc and pp
                     // is different of null

                     select new SearchUserResult
                     {
                         PersonID = p.UPID,
                         UserName = pu.Username,
                         Email = pe.Email, // pe != null ? pe.Email : "",
                         FirstName = p.FirstName,
                         MiddleName = p.MiddleName,
                         LastName = p.LastName,
                         Address = pa.Address1,
                         City = pa.City,
                         StateCode = sc.StateAbbr,
                         StateID = sc.ID,
                         PostalCode = pa.Zip,
                         Phone = pp.PhoneNumber,
                         CountryCode = sc.LU_Country.Name,
                         CountryID = sc.LU_Country.ID
                     });

        if (!string.IsNullOrEmpty(userName))
            users = users.Where(a => a.UserName.Contains(userName));

        if (!string.IsNullOrEmpty(email))
            users = users.Where(b => b.Email != null && b.Email.Contains(email));

        if (!string.IsNullOrEmpty(firstName))
            users = users.Where(c => c.FirstName.Contains(firstName));

        if (!string.IsNullOrEmpty(lastName))
            users = users.Where(d => d.LastName.Contains(lastName));

        if (!string.IsNullOrEmpty(city))
            users = users.Where(e => e.City.Contains(city));

        if (stateID != null && stateID != 0)
        {
            users = users.Where(f => f.StateID == stateID);
        }

        if (!string.IsNullOrEmpty(postalCode))
            users = users.Where(g => g.PostalCode.Contains(postalCode));

        if (countryID != null && countryID != 0)
        {
            users = users.Where(h => h.CountryID == countryID);
        }

        // finally, you can execute the query
        return users.ToList();
    }
}

如果您想了解有关LINQ的更多信息,建议您阅读Syncfusion ebook about LINQ

我希望它对您有所帮助,如果有,请将其标记为答案。