Linq查询时机输出

时间:2015-11-04 20:59:27

标签: asp.net-mvc linq

我有这个查询使用我创建的DBContext实体。

var referral = entities.StudentReferrals.Where(x => x.ReferralID == p && x.SchoolYear == year).FirstOrDefault();

当我删除x.SchoolYear == year时,查询工作正常,但使用它我的查询超时。与我期望发生的情况相反,我预计通过Where子句限制缩小查询的次数越多,它越不可能超时。

SchoolYear是查询中的一个字段,查询本身是有效的,当我在SQL Studio管理器中执行查询时,它会在不到一秒的时间内返回结果。

我的困惑是,为什么在Where子句中添加约束会导致查询超时?

x.SchoolYearyear都是字符串。

完整查询是......

SELECT     [Extent1].[BirthDate] AS [BirthDate],     
    [Extent1].[LegalFirstName] AS [LegalFirstName],     
    [Extent1].[LegalLastName] AS [LegalLastName],     
    [Extent1].[PreferredFirstName] AS [PreferredFirstName],     
    [Extent1].[PreferredLastName] AS [PreferredLastName],     
    [Extent1].[StudentNumber] AS [StudentNumber],     
    [Extent1].[LegacyStudentNumber] AS [LegacyStudentNumber],     
    [Extent1].[TranscriptSchoolCode] AS [TranscriptSchoolCode],     
    [Extent1].[OEN] AS [OEN],     
    [Extent1].[StatusIndicator] AS [StatusIndicator],     
    [Extent1].[SchoolYear] AS [SchoolYear],     
    [Extent1].[ReferralID] AS [ReferralID],     
    [Extent1].[PersonID] AS [PersonID],     
    [Extent1].[Active] AS [Active],     
    [Extent1].[ServiceTypeID] AS [ServiceTypeID],     
    [Extent1].[IsSchoolActive] AS [IsSchoolActive],     
    [Extent1].[Principal] AS [Principal],     
    [Extent1].[SchoolName] AS [SchoolName],     
    [Extent1].[SchoolCode] AS [SchoolCode],     
    [Extent1].[NearNorthSchoolCode] AS [NearNorthSchoolCode],     
    [Extent1].[TranscriptSchoolPrincipal] AS [TranscriptSchoolPrincipal],     
    [Extent1].[TranscriptSchoolName] AS [TranscriptSchoolName],     
    [Extent1].[TranscriptNearNorthSchoolCode] AS [TranscriptNearNorthSchoolCode],     
    [Extent1].[GuardianFirstName] AS [GuardianFirstName],     
    [Extent1].[GuardianLastName] AS [GuardianLastName],     
    [Extent1].[AreaCode] AS [AreaCode],     
    [Extent1].[ContactNo] AS [ContactNo],     
    [Extent1].[ReferredByFirstName] AS [ReferredByFirstName],     
    [Extent1].[ReferredByLastName] AS [ReferredByLastName],     
    [Extent1].[ReferredDate] AS [ReferredDate],     
    [Extent1].[Reason] AS [Reason],     
    [Extent1].[gender] AS [gender],     
    [Extent1].[grade] AS [grade],     
    [Extent1].[HomeroomTeacher] AS [HomeroomTeacher],     
    [Extent1].[IntakeTeamMember] AS [IntakeTeamMember],     
    [Extent1].[IntakeMemberID] AS [IntakeMemberID]    
FROM (SELECT     [StudentReferrals].[BirthDate] AS [BirthDate],     
        [StudentReferrals].[LegalFirstName] AS [LegalFirstName],
        [StudentReferrals].[LegalLastName] AS [LegalLastName],     
        [StudentReferrals].[PreferredFirstName] AS [PreferredFirstName],     
        [StudentReferrals].[PreferredLastName] AS [PreferredLastName],     
        [StudentReferrals].[gender] AS [gender],     
        [StudentReferrals].[StudentNumber] AS [StudentNumber],     
        [StudentReferrals].[LegacyStudentNumber] AS [LegacyStudentNumber],     
        [StudentReferrals].[TranscriptSchoolCode] AS [TranscriptSchoolCode],     
        [StudentReferrals].[OEN] AS [OEN],     
        [StudentReferrals].[StatusIndicator] AS [StatusIndicator],     
        [StudentReferrals].[SchoolYear] AS [SchoolYear],     
        [StudentReferrals].[grade] AS [grade],     
        [StudentReferrals].[ReferralID] AS [ReferralID],     
        [StudentReferrals].[PersonID] AS [PersonID],     
        [StudentReferrals].[Active] AS [Active],     
        [StudentReferrals].[ServiceTypeID] AS [ServiceTypeID],     
        [StudentReferrals].[IsSchoolActive] AS [IsSchoolActive],     
        [StudentReferrals].[Principal] AS [Principal],     
        [StudentReferrals].[SchoolName] AS [SchoolName],     
        [StudentReferrals].[SchoolCode] AS [SchoolCode],     
        [StudentReferrals].[NearNorthSchoolCode] AS [NearNorthSchoolCode],     
        [StudentReferrals].[TranscriptSchoolPrincipal] AS [TranscriptSchoolPrincipal],     
        [StudentReferrals].[TranscriptSchoolName] AS [TranscriptSchoolName],     
        [StudentReferrals].[TranscriptNearNorthSchoolCode] AS [TranscriptNearNorthSchoolCode],     
        [StudentReferrals].[GuardianFirstName] AS [GuardianFirstName],     
        [StudentReferrals].[GuardianLastName] AS [GuardianLastName],     
        [StudentReferrals].[AreaCode] AS [AreaCode],     
        [StudentReferrals].[ContactNo] AS [ContactNo],     
        [StudentReferrals].[ReferredByFirstName] AS [ReferredByFirstName],     
        [StudentReferrals].[ReferredByLastName] AS [ReferredByLastName],     
        [StudentReferrals].[ReferredDate] AS [ReferredDate],     
        [StudentReferrals].[IntakeTeamMember] AS [IntakeTeamMember],     
        [StudentReferrals].[IntakeMemberID] AS [IntakeMemberID],     
        [StudentReferrals].[Reason] AS [Reason],     
        [StudentReferrals].[HomeroomTeacher] AS [HomeroomTeacher]    
        FROM [dbo].[StudentReferrals] AS [StudentReferrals]) AS [Extent1]    
        WHERE ([Extent1].[ReferralID] = @p__linq__0) AND ([Extent1].[SchoolYear] = @p__linq__1)

这是StudentReferral定义......

SELECT        TOP (100) PERCENT p.person_id AS PersonID, p.birth_date AS BirthDate, p.legal_first_name AS LegalFirstName, p.legal_surname AS LegalLastName, p.preferred_first_name AS PreferredFirstName, 
                         p.preferred_surname AS PreferredLastName, p.gender, p.student_no AS StudentNumber, p.legacy_student_number AS LegacyStudentNumber, p.transcript_school_code AS TranscriptSchoolCode, 
                         p.oen_number AS OEN, s.status_indicator_code AS StatusIndicator, s.school_year AS SchoolYear, s.grade, CAST(CASE WHEN PATINDEX('%[^A-Za-z]%', s.Grade) = 0 THEN 1 ELSE CASE WHEN CAST(s.Grade AS int)
                          < 9 THEN 1 ELSE 0 END END AS bit) AS IsElementary, t.SchoolName, t.SchoolCode, t.NearNorthSchoolCode, pg.person_id AS GuardianID, pg.legal_first_name AS GuardianFirstName, 
                         pg.legal_surname AS GuardianLastName, pt.area_code AS AreaCode, pt.phone_no AS ContactNo, pt.email_account AS Email
FROM            Trillium.dbo.persons AS p INNER JOIN
                         Trillium.dbo.student_registrations AS s ON s.person_id = p.person_id INNER JOIN
                         dbo.Schools AS t ON t.SchoolCode = s.school_code INNER JOIN
                         NNDSB_AD_Routines.dbo.Students_Trillium_Guardians AS g ON s.person_id = g.student_person_id INNER JOIN
                         Trillium.dbo.persons AS pg ON g.contact_person_id = pg.person_id INNER JOIN
                         Trillium.dbo.person_telecom AS pt ON pg.person_id = pt.person_id
WHERE        (s.status_indicator_code IN ('Active', 'PreReg')) AND (pt.telecom_type_name = 'home')
GROUP BY p.person_id, p.birth_date, p.legal_first_name, p.legal_surname, p.preferred_first_name, p.preferred_surname, p.gender, p.student_no, p.legacy_student_number, p.transcript_school_code, p.oen_number, 
                         s.status_indicator_code, s.school_year, s.grade, CAST(CASE WHEN PATINDEX('%[^A-Za-z]%', s.Grade) = 0 THEN 1 ELSE CASE WHEN CAST(s.Grade AS int) < 9 THEN 1 ELSE 0 END END AS bit), t.SchoolName, 
                         t.SchoolCode, t.NearNorthSchoolCode, pg.person_id, pg.legal_first_name, pg.legal_surname, pt.area_code, pt.phone_no, pt.email_account, g.primary_contact_priority
ORDER BY g.primary_contact_priority

2 个答案:

答案 0 :(得分:1)

我几乎可以保证EF生成的查询和您在SSMS中执行的查询不是完全相同的SELECT语句。你可能写了类似Stephen Byrne在答案中的内容,即

SELECT * from StudentReferrals WHERE ReferallID=1 AND SchoolYear='2015'

此时,此查询没有TOP限定符,由于FirstOrDefault调用的存在,您的EF查询可能会出现这种情况。

您的第一步应该是使用SQL Profiler之类的东西并获取EF生成的实际查询。由于正在生成的查询类型,优化器可能会选择执行表扫描。

这可能不会有任何区别,但您也可以尝试将查询重写为:

var referral = entities.StudentReferrals.FirstOrDefault(x => x.ReferralID == p && x.SchoolYear == year);

例如,当我针对我的数据库编写以下查询时:

OrganizationalNodes.FirstOrDefault(on => on.Name == "Justice League")

EF生成以下SQL:

SELECT 
    [Limit1].[C1] AS [C1], 
    [Limit1].[Id] AS [Id], 
    -- columns omitted for brevity
    FROM ( SELECT TOP (1) 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Name] AS [Name], 
        -- columns omitted for brevity
        '0X0X' AS [C1]
        FROM  [dbo].[OrganizationalItems] AS [Extent1]
        INNER JOIN [dbo].[OrganizationalNodes] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Id]
        WHERE N'Justice League' = [Extent1].[Name]
    )  AS [Limit1]

答案 1 :(得分:0)

好吧,回答这个问题

  

为什么在Where子句中添加约束会导致查询超时

最可能的原因是表中有大量数据,但没有索引涵盖SchoolYear列。因此,当您在WHERE子句中包含in时,会导致表扫描(因为必须检查每一行以查看它是否应包含在结果集中)

如果您使用SQL Server Management Studio并手动编写查询,例如

SELECT * from StudentReferrals WHERE ReferallID=1 AND SchoolYear='2015'

然后包括实际的执行计划(查询 - >包括实际估算计划),然后您将获得执行细分,如果涉及表扫描,将清楚地向您显示。如果有的话,创建一个索引来覆盖&#34;覆盖&#34;涉及的列,它应该解决你的问题。

更新

另一个可能的解决方案是运行DBCC FREEPROCCACHE以清除任何缓存的执行计划,以防出于某些原因SQL Server为实体框架生成的任何查询选择了疯狂的东西。