EF 6代码优先查询非常慢

本文关键字:查询 非常 代码 EF | 更新日期: 2023-09-27 18:18:57

我有一个应用程序,需要根据用户选择进行查询过滤。这个查询经常运行。我首先使用代码。我需要帮助找到一个更好的方式来执行这个类似的查询。现在执行这个查询需要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,查询将仅对先前过滤的结果执行。这样,任何后续查询都将花费最少的时间。但是,初始查询耗时太长。

有什么建议吗?执行此查询的更好方法是什么?

EF 6代码优先查询非常慢

编写查询!

所有这些条件使得查询优化器几乎不可能计算出一个好的查询计划。大多数情况下,只输入几个条件,但所有其他谓词仍然是查询的一部分。它们将简单地计算为真或假,但问题是它们太多了,可能的优化数量呈指数级增长。如这里所说:

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

所以如果你减少谓词的数量,查询优化器就有更好的机会找到一个好的执行计划。

一般的方法是

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这样的谓词构建器来组合查询。

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

创建一个存储过程,确保有适当的索引,并使用存储过程而不是EF表达式运行查询。它将执行好得多

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

或者您可以使用。sqlquery调用存储过程:_db.Database返回。SqlQuery("exec DB_SP_FIND_MATCHING_RENTS @ statid @cityId", statid, cityId);

关于。sqlquery的更多信息http://msdn.microsoft.com/en-us/data/jj592907.aspx