具有多个连接和分组的SQL查询的Linq版本

时间:2012-03-06 22:20:39

标签: sql performance linq entity-framework

尝试从linq中的旧数据库编写此查询时,我遇到了性能问题。有没有更好的方法在linq中编写以下sql查询。

sql查询运行时间不到2秒,而当前的linq表达式需要6秒钟。

这是来自SQL 2008R2数据库。

这是sql查询

SELECT  People.ID,
        A.GameKey, 
        ClubCode, 
        case
            WHEN ClubCode = Home_TM_CD then Visit_TM_CD
            WHEN ClubCode = Visit_TM_CD then Home_TM_CD
        end as Opponent,            
        count(case when (ClubCode <> PossessionTeam and STPlayType = 0)  then 'super' end) as super_plays,
        (SELECT count(PlayID) 
         FROM   PLAY_LIST B 
         WHERE  A.GameKey = B.GameKey
         AND    ClubCode <> PossessionTeam 
         AND    PossessionTeam <> ''
         AND    STPlayType = 0 
         GROUP BY A.GameKey, A.ClubCode) as Total_Super_Play,
        count(case when (ClubCode = PossessionTeam and STPlayType = 0) then 'plays' end) as plays,
        (SELECT count(PlayID) 
         FROM   PLAY_LIST B 
         WHERE  A.GameKey = B.GameKey
         AND    ClubCode = PossessionTeam 
         AND    STPlayType = 0 
         GROUP BY A.GameKey, A.ClubCode) as Total_Play,         
        Season,
        Season_Type,
        Week,
        Game_DT
    FROM    PEOPLE
    INNER JOIN PEOPLE_PARTICIPATION A ON People.ID = A.ID
    inner join GAME on GameKey  = gamekey
    inner join PLAY_LIST on PLAY_LIST.GameKey = A.GameKey AND PLAY_LIST.PlayID = A.PlayID
    WHERE   Season = 2011       
    and     People.ID = 1
    group by    People.ID,
                Season,
                Season_Type,
                Week,
                Game_DT,
                A.GameKey,
                ClubCode,
                Home_TM_CD, 
                Visit_TM_CD
    order by Season, 
             CASE WHEN Season_Type = 'Reg' THEN 1 ELSE 2 END, week, People.ID

这是我到目前为止的linq表达式

IQueryable<ProViewModel> playerList = (from people in db.PEOPLE
join participation in db.PARTICIPATION on people.ID equals participation.ID
join game in db.GAME on participation.GameKey equals game.Gamekey    
join playlist in db.PLAY_LIST on new { gamekey = participation.GameKey, playID = participation.PlayID } equals new { gamekey = playlist.GameKey, playID = playlist.PlayID }                                                                                    
where people.ID == 1 &&
game.Season == 2011
group playlist by new PeopleParticipationGroup{
   ID = people.ID,
   SEASON = game.Season,
   SEASON_TYPE = game.Season_Type,
   WEEK = game.Week,
   GAME_DT = game.Game_DT,
   GameKey = participation.GameKey,
   ClubCode = participation.ClubCode,
   HOME_TM_CD = game.Home_TM_CD,
   VISIT_TM_CD = game.Visit_TM_CD
} into groupedPeople
orderby groupedPeople.Key.SEASON                                                  
select new PeopleViewModel 
{   
   ID = groupedPeople.Key.ID,
   SEASON_TYPE = groupedPeople.Key.SEASON_TYPE,
   WEEK = groupedPeople.Key.WEEK,
   SEASON_TYPE_SORT = 
   (
    groupedPeople.Key.SEASON_TYPE == "REG" ? 1 :
    groupedPeople.Key.SEASON_TYPE == "POST" ? 2 : 3
   ),
   GAME_DT = groupedPeople.Key.GAME_DT,
   SEASON = groupedPeople.Key.SEASON,
   GameKey = groupedPeople.Key.GameKey,
   ClubCode = groupedPeople.Key.ClubCode,
   Opponent = 
   (
    groupedPeople.Key.ClubCode == groupedPeople.Key.HOME_TM_CD ? groupedPeople.Key.VISIT_TM_CD : groupedPeople.Key.HOME_TM_CD
   ),
   HOME_TM_CD = groupedPeople.Key.HOME_TM_CD,
   VISIT_TM_CD = groupedPeople.Key.VISIT_TM_CD,                                                       
   PLAYS = (from t in groupedPeople
                      where t.PossessionTeam == groupedPeople.Key.ClubCode && 
                      t.STPlayType == 0
                      select t).Count(),                                                       
   TOTAL_PLAYS = (from p in db.PLAY_LIST
                            where p.GameKey == groupedPeople.Key.GameKey && 
                            p.PossessionTeam == groupedPeople.Key.ClubCode && 
                            p.PossessionTeam != "" &&                                                                                 
                            p.STPlayType == 0
                            select p).Count(),
   SUPER_PLAYS = (from t in groupedPeople
                      where t.PossessionTeam != groupedPeople.Key.ClubCode && 
                      t.STPlayType == 0
                      select t).Count(),
   TOTAL_SUPER_PLAYS = (from p in db.PLAY_LIST
                            where p.GameKey == groupedPeople.Key.GameKey &&
                            p.PossessionTeam == groupedPeople.Key.ClubCode &&
                            p.PossessionTeam == "" &&
                            p.STPlayType == 0
                            select p).Count(),                                                       
}); ;

1 个答案:

答案 0 :(得分:0)

我不完全确定如何编译查询,以及完成了多少优化。如果它按预期工作并按查询顺序将查询转换为linq函数调用,那么重新排列顺序可能有所帮助。

例如,您可以删除

where people.ID == 1 &&
game.Season == 2011

并将db.PEOPLE替换为db.PEOPLE.where(p => p.id == 1),替换为db.GAME

这样可以避免加入后来被丢弃的结果。由于你有这些常数,所以可能值得将它们从分组中取出并直接进入选择。

另一方面,假设这是LINQ to SQL,那么上面的内容可能无济于事,您可以使用db.Log来查看SQL中查询的内容。然后,您可以重新排列,直到您的LINQ匹配或改进原始SQL。