views:

168

answers:

1

I've been running a trace on some of the queries Linq is generating and they seem very unoptimized and clumsy.

I realise you dont know my data structure but is tere anything immidiatly wrong with the following linq query

    IQueryable<Tasks> tl = db.Tasks
                                .Include("Catagories")
                                .Include("Projects")
                                .Include("TaskStatuses")
                                .Include("AssignedTo")
                                .Where
                                    (t => (t.TaskStatuses.TaskStatusId.Equals(currentStatus) | currentStatus == -1) &
                                    (t.Projects.ProjectId.Equals(projectId) | projectId == -1) &
                                    (t.Subject.Contains(SearchText) | t.Description.Contains(SearchText) | SearchText == "" | SearchText == null) &
                                    (t.Projects.Active == true) & 
                                    (t.Catagories.Active == true || t.Catagories==null) &
                                    (t.LoggedBy.UserProfile.Companies.CompanyId == CompanyId) &
                                    (assignedToGuid == rnd | t.AssignedTo.UserId.Equals(assignedToGuid))).OrderBy(SortField + " " + SortOrder);

When it runs it generates this SQL query

    exec sp_executesql N'SELECT 
[Project1].[C1] AS [C1], 
[Project1].[TaskId] AS [TaskId], 
[Project1].[Subject] AS [Subject], 
[Project1].[Description] AS [Description], 
[Project1].[EstimateDays] AS [EstimateDays], 
[Project1].[EstimateHours] AS [EstimateHours], 
[Project1].[DateLogged] AS [DateLogged], 
[Project1].[DateModified] AS [DateModified], 
[Project1].[AssignedTo] AS [AssignedTo], 
[Project1].[C2] AS [C2], 
[Project1].[CatagoryId] AS [CatagoryId], 
[Project1].[CatagoryName] AS [CatagoryName], 
[Project1].[CreatedOn] AS [CreatedOn], 
[Project1].[Active] AS [Active], 
[Project1].[CreatedBy] AS [CreatedBy], 
[Project1].[C3] AS [C3], 
[Project1].[ProjectId] AS [ProjectId], 
[Project1].[ProjectName] AS [ProjectName], 
[Project1].[CreatedOn1] AS [CreatedOn1], 
[Project1].[Active1] AS [Active1], 
[Project1].[CreatedBy1] AS [CreatedBy1], 
[Project1].[TaskStatusId] AS [TaskStatusId], 
[Project1].[StatusName] AS [StatusName], 
[Project1].[C4] AS [C4], 
[Project1].[ApplicationId] AS [ApplicationId], 
[Project1].[UserId] AS [UserId], 
[Project1].[UserName] AS [UserName], 
[Project1].[LoweredUserName] AS [LoweredUserName], 
[Project1].[MobileAlias] AS [MobileAlias], 
[Project1].[IsAnonymous] AS [IsAnonymous], 
[Project1].[LastActivityDate] AS [LastActivityDate], 
[Project1].[UserId1] AS [UserId1], 
[Project1].[UserId2] AS [UserId2]
FROM ( SELECT 
    [Filter1].[TaskId] AS [TaskId], 
    [Filter1].[Subject] AS [Subject], 
    [Filter1].[Description] AS [Description], 
    [Filter1].[AssignedTo] AS [AssignedTo], 
    [Filter1].[EstimateDays] AS [EstimateDays], 
    [Filter1].[EstimateHours] AS [EstimateHours], 
    [Filter1].[DateLogged] AS [DateLogged], 
    [Filter1].[DateModified] AS [DateModified], 
    [Filter1].[CatagoryId1] AS [CatagoryId], 
    [Filter1].[CatagoryName] AS [CatagoryName], 
    [Filter1].[CreatedBy1] AS [CreatedBy], 
    [Filter1].[CreatedOn1] AS [CreatedOn], 
    [Filter1].[Active1] AS [Active], 
    [Filter1].[ProjectId1] AS [ProjectId], 
    [Filter1].[ProjectName1] AS [ProjectName], 
    [Filter1].[CreatedOn2] AS [CreatedOn1], 
    [Filter1].[Active2] AS [Active1], 
    [Filter1].[CreatedBy2] AS [CreatedBy1], 
    [Filter1].[TaskStatusId1] AS [TaskStatusId], 
    [Filter1].[StatusName] AS [StatusName], 
    [Filter1].[ApplicationId1] AS [ApplicationId], 
    [Filter1].[UserId1] AS [UserId], 
    [Filter1].[UserName1] AS [UserName], 
    [Filter1].[LoweredUserName1] AS [LoweredUserName], 
    [Filter1].[MobileAlias1] AS [MobileAlias], 
    [Filter1].[IsAnonymous1] AS [IsAnonymous], 
    [Filter1].[LastActivityDate1] AS [LastActivityDate], 
    [Filter1].[UserId2] AS [UserId1], 
    [Join12].[UserId3] AS [UserId2], 
    1 AS [C1], 
    1 AS [C2], 
    1 AS [C3], 
    1 AS [C4]
    FROM   (SELECT [Extent1].[TaskId] AS [TaskId], [Extent1].[Subject] AS [Subject], [Extent1].[Description] AS [Description], [Extent1].[ProjectId] AS [ProjectId2], [Extent1].[TaskStatusId] AS [TaskStatusId2], [Extent1].[LoggedBy] AS [LoggedBy], [Extent1].[AssignedTo] AS [AssignedTo], [Extent1].[EstimateDays] AS [EstimateDays], [Extent1].[EstimateHours] AS [EstimateHours], [Extent1].[DateLogged] AS [DateLogged], [Extent1].[DateModified] AS [DateModified], [Extent1].[CatagoryId] AS [CatagoryId2], [Extent2].[ProjectId] AS [ProjectId3], [Extent2].[ProjectName] AS [ProjectName2], [Extent2].[CreatedOn] AS [CreatedOn3], [Extent2].[CreatedBy] AS [CreatedBy3], [Extent2].[Active] AS [Active3], [Extent3].[CatagoryId] AS [CatagoryId1], [Extent3].[CatagoryName] AS [CatagoryName], [Extent3].[CreatedBy] AS [CreatedBy1], [Extent3].[CreatedOn] AS [CreatedOn1], [Extent3].[Active] AS [Active1], [Join3].[ApplicationId2], [Join3].[UserId4], [Join3].[UserName2], [Join3].[LoweredUserName2], [Join3].[MobileAlias2], [Join3].[IsAnonymous2], [Join3].[LastActivityDate2], [Join3].[UserId5], [Join3].[CompanyId1], [Join3].[Forename1], [Join3].[Surname1], [Join3].[Active4], [Extent6].[UserId] AS [UserId6], [Extent6].[CompanyId] AS [CompanyId2], [Extent6].[Forename] AS [Forename2], [Extent6].[Surname] AS [Surname2], [Extent6].[Active] AS [Active5], [Extent7].[ProjectId] AS [ProjectId1], [Extent7].[ProjectName] AS [ProjectName1], [Extent7].[CreatedOn] AS [CreatedOn2], [Extent7].[CreatedBy] AS [CreatedBy4], [Extent7].[Active] AS [Active2], [Extent8].[ProjectId] AS [ProjectId4], [Extent8].[ProjectName] AS [ProjectName3], [Extent8].[CreatedOn] AS [CreatedOn4], [Extent8].[CreatedBy] AS [CreatedBy2], [Extent8].[Active] AS [Active6], [Extent9].[TaskStatusId] AS [TaskStatusId1], [Extent9].[StatusName] AS [StatusName], [Extent10].[ApplicationId] AS [ApplicationId1], [Extent10].[UserId] AS [UserId1], [Extent10].[UserName] AS [UserName1], [Extent10].[LoweredUserName] AS [LoweredUserName1], [Extent10].[MobileAlias] AS [MobileAlias1], [Extent10].[IsAnonymous] AS [IsAnonymous1], [Extent10].[LastActivityDate] AS [LastActivityDate1], [Join10].[ApplicationId3], [Join10].[UserId7], [Join10].[UserName3], [Join10].[LoweredUserName3], [Join10].[MobileAlias3], [Join10].[IsAnonymous3], [Join10].[LastActivityDate3], [Join10].[ApplicationId4], [Join10].[UserId2], [Join10].[Password], [Join10].[PasswordFormat], [Join10].[PasswordSalt], [Join10].[MobilePIN], [Join10].[Email], [Join10].[LoweredEmail], [Join10].[PasswordQuestion], [Join10].[PasswordAnswer], [Join10].[IsApproved], [Join10].[IsLockedOut], [Join10].[CreateDate], [Join10].[LastLoginDate], [Join10].[LastPasswordChangedDate], [Join10].[LastLockoutDate], [Join10].[FailedPasswordAttemptCount], [Join10].[FailedPasswordAttemptWindowStart], [Join10].[FailedPasswordAnswerAttemptCount], [Join10].[FailedPasswordAnswerAttemptWindowStart], [Join10].[Comment]
     FROM          [dbo].[Tasks] AS [Extent1]
     INNER JOIN [dbo].[Projects] AS [Extent2] ON [Extent1].[ProjectId] = [Extent2].[ProjectId]
     LEFT OUTER JOIN [dbo].[Catagories] AS [Extent3] ON [Extent1].[CatagoryId] = [Extent3].[CatagoryId]
     LEFT OUTER JOIN  (SELECT [Extent4].[ApplicationId] AS [ApplicationId2], [Extent4].[UserId] AS [UserId4], [Extent4].[UserName] AS [UserName2], [Extent4].[LoweredUserName] AS [LoweredUserName2], [Extent4].[MobileAlias] AS [MobileAlias2], [Extent4].[IsAnonymous] AS [IsAnonymous2], [Extent4].[LastActivityDate] AS [LastActivityDate2], [Extent5].[UserId] AS [UserId5], [Extent5].[CompanyId] AS [CompanyId1], [Extent5].[Forename] AS [Forename1], [Extent5].[Surname] AS [Surname1], [Extent5].[Active] AS [Active4]
      FROM  [dbo].[aspnet_Users] AS [Extent4]
      LEFT OUTER JOIN [dbo].[UserProfile] AS [Extent5] ON [Extent4].[UserId] = [Extent5].[UserId] ) AS [Join3] ON [Extent1].[AssignedTo] = [Join3].[UserId4]
     INNER JOIN [dbo].[UserProfile] AS [Extent6] ON [Join3].[UserId5] = [Extent6].[UserId]
     LEFT OUTER JOIN [dbo].[Projects] AS [Extent7] ON [Extent1].[ProjectId] = [Extent7].[ProjectId]
     LEFT OUTER JOIN [dbo].[Projects] AS [Extent8] ON [Extent1].[ProjectId] = [Extent8].[ProjectId]
     LEFT OUTER JOIN [dbo].[TaskStatuses] AS [Extent9] ON [Extent1].[TaskStatusId] = [Extent9].[TaskStatusId]
     LEFT OUTER JOIN [dbo].[aspnet_Users] AS [Extent10] ON [Extent1].[LoggedBy] = [Extent10].[UserId]
     LEFT OUTER JOIN  (SELECT [Extent11].[ApplicationId] AS [ApplicationId3], [Extent11].[UserId] AS [UserId7], [Extent11].[UserName] AS [UserName3], [Extent11].[LoweredUserName] AS [LoweredUserName3], [Extent11].[MobileAlias] AS [MobileAlias3], [Extent11].[IsAnonymous] AS [IsAnonymous3], [Extent11].[LastActivityDate] AS [LastActivityDate3], [Extent12].[ApplicationId] AS [ApplicationId4], [Extent12].[UserId] AS [UserId2], [Extent12].[Password] AS [Password], [Extent12].[PasswordFormat] AS [PasswordFormat], [Extent12].[PasswordSalt] AS [PasswordSalt], [Extent12].[MobilePIN] AS [MobilePIN], [Extent12].[Email] AS [Email], [Extent12].[LoweredEmail] AS [LoweredEmail], [Extent12].[PasswordQuestion] AS [PasswordQuestion], [Extent12].[PasswordAnswer] AS [PasswordAnswer], [Extent12].[IsApproved] AS [IsApproved], [Extent12].[IsLockedOut] AS [IsLockedOut], [Extent12].[CreateDate] AS [CreateDate], [Extent12].[LastLoginDate] AS [LastLoginDate], [Extent12].[LastPasswordChangedDate] AS [LastPasswordChangedDate], [Extent12].[LastLockoutDate] AS [LastLockoutDate], [Extent12].[FailedPasswordAttemptCount] AS [FailedPasswordAttemptCount], [Extent12].[FailedPasswordAttemptWindowStart] AS [FailedPasswordAttemptWindowStart], [Extent12].[FailedPasswordAnswerAttemptCount] AS [FailedPasswordAnswerAttemptCount], [Extent12].[FailedPasswordAnswerAttemptWindowStart] AS [FailedPasswordAnswerAttemptWindowStart], [Extent12].[Comment] AS [Comment]
      FROM  [dbo].[aspnet_Users] AS [Extent11]
      LEFT OUTER JOIN [dbo].[aspnet_Membership] AS [Extent12] ON [Extent11].[UserId] = [Extent12].[UserId] ) AS [Join10] ON [Extent1].[LoggedBy] = [Join10].[UserId7]
     WHERE (1 = [Extent2].[Active]) AND ((1 = [Extent3].[Active]) OR ([Extent3].[CatagoryId] IS NULL)) ) AS [Filter1]
    LEFT OUTER JOIN  (SELECT [Extent13].[ApplicationId] AS [ApplicationId], [Extent13].[UserId] AS [UserId8], [Extent13].[UserName] AS [UserName], [Extent13].[LoweredUserName] AS [LoweredUserName], [Extent13].[MobileAlias] AS [MobileAlias], [Extent13].[IsAnonymous] AS [IsAnonymous], [Extent13].[LastActivityDate] AS [LastActivityDate], [Extent14].[UserId] AS [UserId3], [Extent14].[CompanyId] AS [CompanyId], [Extent14].[Forename] AS [Forename], [Extent14].[Surname] AS [Surname], [Extent14].[Active] AS [Active]
     FROM  [dbo].[aspnet_Users] AS [Extent13]
     LEFT OUTER JOIN [dbo].[UserProfile] AS [Extent14] ON [Extent13].[UserId] = [Extent14].[UserId] ) AS [Join12] ON [Filter1].[LoggedBy] = [Join12].[UserId8]
    WHERE (([Filter1].[TaskStatusId2] = @p__linq__49) OR (-1 = @p__linq__50)) AND (([Filter1].[ProjectId2] = @p__linq__51) OR (-1 = @p__linq__52)) AND (((CAST(CHARINDEX(@p__linq__53, [Filter1].[Subject]) AS int)) > 0) OR ((CAST(CHARINDEX(@p__linq__54, [Filter1].[Description]) AS int)) > 0) OR (N'''' = @p__linq__55) OR (@p__linq__56 IS NULL)) AND ([Filter1].[CompanyId2] = @p__linq__57) AND ((@p__linq__58 = @p__linq__59) OR ([Filter1].[LoggedBy] = @p__linq__60))
)  AS [Project1]
ORDER BY [Project1].[TaskId] ASC',N'@p__linq__49 int,@p__linq__50 int,@p__linq__51 int,@p__linq__52 int,@p__linq__53 nvarchar(4000),@p__linq__54 nvarchar(4000),@p__linq__55 nvarchar(4000),@p__linq__56 nvarchar(4000),@p__linq__57 int,@p__linq__58 uniqueidentifier,@p__linq__59 uniqueidentifier,@p__linq__60 uniqueidentifier',@p__linq__49=1,@p__linq__50=1,@p__linq__51=2,@p__linq__52=2,@p__linq__53=NULL,@p__linq__54=NULL,@p__linq__55=NULL,@p__linq__56=NULL,@p__linq__57=1,@p__linq__58='00000000-0000-0000-0000-000000000000',@p__linq__59='00000000-0000-0000-0000-000000000000',@p__linq__60='00000000-0000-0000-0000-000000000000'

I'm sure there must be a way to get Linq to generate more friendly SQL. If I wrote this same query it could be done in about 5 joins and no inner selects, is it possible to get Linq to tidy this up?

Thanks

Gavin

+1  A: 

The large query LINQ to EF creates is just a shortcoming of the first release of the Entity Framework. However, your query contains the phrase .OrderBy(SortField + " " + SortOrder), I believe the preffered way to write this would be .OrderBy(SortField).ThenBy(SortOrder). Also, is there any reason that you are using | instead of || and & instead of && in some places?

IQueryable<Tasks> tl = db.Tasks
                                .Include("Catagories")
                                .Include("Projects")
                                .Include("TaskStatuses")
                                .Include("AssignedTo")
                                .Where
                                    (t => (t.TaskStatuses.TaskStatusId.Equals(currentStatus) | currentStatus == -1) &
                                    (t.Projects.ProjectId.Equals(projectId) | projectId == -1) &
                                    (t.Subject.Contains(SearchText) | t.Description.Contains(SearchText) | SearchText == "" | SearchText == null) &
                                    (t.Projects.Active == true) & 
                                    (t.Catagories.Active == true || t.Catagories==null) &
                                    (t.LoggedBy.UserProfile.Companies.CompanyId == CompanyId) &
                                    (assignedToGuid == rnd | t.AssignedTo.UserId.Equals(assignedToGuid))).OrderBy(SortField + " " + SortOrder);
Tion