EF 6 Code First Query非常慢

时间:2014-08-21 19:21:49

标签: c# performance entity-framework ef-code-first

我有一个应用程序,需要根据用户选择进行查询。此查询经常运行。我先使用代码。我需要帮助才能找到更好的方法来执行此类似的查询。现在这个查询需要2分钟到5分钟才能执行。我有超过11K的行。

var ads = from AllAds in _db.Rents
                      where (myStateId > 0) ? (AllAds.RentAddresses.RentAddressCommunities.RentAddressCities.RentAddressStates.RentAddressStateId == myStateId) : (myStateId == -1)
                      where (myCityId > 0) ? (AllAds.RentAddresses.RentAddressCommunities.RentAddressCities.RentAddressCityId == myCityId) : (myCityId == -1)
                      where (myPropertyTypeId > 0) ? (AllAds.RentPropertytypeId == myPropertyTypeId) : (myPropertyTypeId == -1)
                      where (myPropertyBedroomId > 0) ? (AllAds.RentBedroomtypeId == myPropertyBedroomId) : (myPropertyBedroomId == -1)
                      where (myPropertyBathroomId > 0) ? (AllAds.RentBathroomtypeId == myPropertyBathroomId) : (myPropertyBathroomId == -1)
                      where (MyCommunityId > 0) ? (AllAds.RentAddresses.RentAddressCommunities.RentAddressCommunityName == MyCommunityName) : (MyCommunityId == -1)
                      where (myStreetId > 0) ? (AllAds.RentAddresses.RentAddressStreetAddress == myStreetAddress) : (myStreetId == -1)
                      where (myPostalCodeId > 0) ? (AllAds.RentAddresses.RentAddressZipCode == myPostalCodeName) : (myPostalCodeId == -1)
                      where (myMonthlyRentId == 500) ? (AllAds.RentRent <= 499) :
                       (myMonthlyRentId == 700) ? (AllAds.RentRent >= 500 && AllAds.RentRent <= 699) :
                       (myMonthlyRentId == 900) ? (AllAds.RentRent >= 700 && AllAds.RentRent <= 899) :
                       (myMonthlyRentId == 1200) ? (AllAds.RentRent >= 900 && AllAds.RentRent <= 1199) :
                       (myMonthlyRentId == 1500) ? (AllAds.RentRent >= 1200 && AllAds.RentRent <= 1499) :
                       (myMonthlyRentId == 2000) ? (AllAds.RentRent >= 1500 && AllAds.RentRent <= 1999) :
                       (myMonthlyRentId == 2500) ? (AllAds.RentRent >= 2000 && AllAds.RentRent <= 2499) :
                       (myMonthlyRentId == 50000) ? (AllAds.RentRent >= 2500) : (myMonthlyRentId == -1)
                      where (mySquareFeetId == 700) ? (AllAds.RentSquareFeet <= 699) :
                      (mySquareFeetId == 900) ? (AllAds.RentSquareFeet >= 700 && AllAds.RentSquareFeet <= 899) :
                      (mySquareFeetId == 1200) ? (AllAds.RentSquareFeet >= 900 && AllAds.RentSquareFeet <= 1199) :
                      (mySquareFeetId == 1500) ? (AllAds.RentSquareFeet >= 1200 && AllAds.RentSquareFeet <= 1499) :
                      (mySquareFeetId == 2000) ? (AllAds.RentSquareFeet >= 1500 && AllAds.RentSquareFeet <= 1999) :
                      (mySquareFeetId == 2500) ? (AllAds.RentSquareFeet >= 2000 && AllAds.RentSquareFeet <= 2499) :
                      (mySquareFeetId == 50000) ? (AllAds.RentSquareFeet >= 2500) : (mySquareFeetId == -1)
                      orderby AllAds.dateCrawled descending, AllAds.dateListed descending
                      select AllAds;
            return ads.ToList<Rent>().AsQueryable();

在此示例中,如果用户选择任何城市,则此查询将使用城市名称执行,并将根据此行进行过滤。 where子句中的其他过滤器将被忽略。

where (myCityId > 0) ? (AllAds.RentAddresses.RentAddressCommunities.RentAddressCities.RentAddressCityId == myCityId) : (myCityId == -1)

我将此查询保存在内存中,以便在用户选择Propertytype时,查询将仅对先前过滤的结果执行。这样,任何后续查询都需要最少的时间。但是,初始查询需要很长时间。

任何建议请!!执行此查询的更好方法是什么?

2 个答案:

答案 0 :(得分:0)

创建存储过程,确保您具有适当的索引,并使用存储的proc而不是EF表达式运行查询。它会更好地执行很多

您仍然可以通过在.edmx中链接存储过程来访问存储过程。 http://msdn.microsoft.com/en-us/library/vstudio/bb896334%28v=vs.100%29.aspx

或者您可以使用.SqlQuery调用存储过程:     return _db.Database.SqlQuery(&#34; exec DB_SP_FIND_MATCHING_RENTS @stateId @ cityId&#34;,stateId,cityId);

有关.SqlQuery的更多信息 http://msdn.microsoft.com/en-us/data/jj592907.aspx

答案 1 :(得分:0)

撰写查询!

所有这些条件使查询优化器几乎不可能计算出良好的查询计划。大多数情况下,只会输入几个条件,但所有其他谓词仍然是查询的一部分。它们只会评估为真或假,但问题是它们中有很多并且可能的优化次数呈指数级增长。正如所说here

  

对于复杂查询,所有可能排列的数量可能很大,因此查询优化器不会评估所有可能性,而是尝试查找足够好的计划&#34;对于给定的查询。这是因为找到一个完美的计划可能并不总是可行的;即使有可能,评估找到完美计划的所有可能性的成本也很容易超过任何性能提升。

因此,如果减少谓词的数量,查询优化器就有可能找到一个好的执行计划。

执行此操作的一般方法是

if (myStateId > 0)
{
    rents = rents
           .Where(AllAds => AllAds.RentAddresses.RentAddressCommunities
                                  .RentAddressCities.RentAddressStates
                                  .RentAddressStateId == myStateId);
}
if (myCityId > 0)
{
    rents = rents
           .Where(AllAds => AllAds.RentAddresses.RentAddressCommunities
                                  .RentAddressCities
                                  .RentAddressCityId == myCityId);
}
if ...

你明白了。

您还可以使用谓词构建器(如Linqkit)撰写查询。

这个想法是只有重要的谓词才会成为查询的一部分。这不仅减少了查询优化器必须处理的执行路径的数量,而且如果用户不输入涉及连接的谓词,还可以节省大量昂贵的连接。

相关问题