2015-01-12 104 views
2

我正在優化我的web應用程序,並遇到瓶頸,從我的linq表達式生成的SQL非常慢。增加linq查詢效率

以下SQL執行公下的第二:

SELECT 
    ISNULL(COUNT(distinct JOBIDNumber),0), 
    ISNULL(SUM(JIMQuantityActual * JIMNetMarginFactor),0), 
    ISNULL(sum((isnull(MATRecoverablePercent,0)/100) * JIMQuantityActual * JIMNetMarginFactor),0), 
    ISNULL(sum(CarbonSaving),0) 
FROM 
    dbo.fn_GetJobsForUser(183486) jb 
    inner join cd_JobMaterial on JIMJobId = jb.JOBIDNumber 
WHERE 
    JOBCollectionDate >= '2014-11-01' 

而由下面的查詢的輸出SQL通過相同的數據佔用秒4和16之間:

DateTime d = new DateTime(2014, 11, 1) 

from job in sp.sp_GetJobsForUser(183486) 
where job.JOBCollectionDate >= d 
join material in UnitOfWork.Repository<cd_JobMaterial>().Queryable() 
on job.JOBIDNumber equals material.JIMJobId 
group material by 1 into f 
select new 
{ 
    Jobs = f.Distinct().Count(), 
    Weight = f.Sum(x=> x.JIMQuantityActual * x.JIMNetMarginFactor), 
    Carbon = f.Sum(x=> x.CarbonSaving), 
    Recovery = f.Sum(x => ((x.MATRecoverablePercent/100) * x.JIMQuantityActual * x.JIMNetMarginFactor)) 
} 

哪個輸出如下:

-- Region Parameters 
DECLARE @contactId Int = 183486 
DECLARE @p__linq__0 DateTime2 = '2014-11-01 00:00:00.0000000' 
-- EndRegion 

SELECT 
    [Project4].[C1] AS [C1], 
    [Project4].[C5] AS [C2], 
    [Project4].[C2] AS [C3], 
    [Project4].[C3] AS [C4], 
    [Project4].[C4] AS [C5] 
FROM (SELECT 
    [Project2].[C1] AS [C1], 
    [Project2].[C2] AS [C2], 
    [Project2].[C3] AS [C3], 
    [Project2].[C4] AS [C4], 
    (SELECT 
     COUNT(1) AS [A1] 
    FROM (SELECT DISTINCT 
     /*Fields omitted for brevity */ 
    FROM [dbo].[fn_GetJobsForUser](@contactId) AS [Extent3] 
    INNER JOIN (SELECT 
     /*Fields omitted for brevity */ 
    FROM [dbo].[cd_JobMaterial] AS [cd_JobMaterial]) AS [Extent4] 
     ON [Extent3].[JOBIDNumber] = [Extent4].[JIMJobId] 
    WHERE ([Extent3].[JOBCollectionDate] >= @p__linq__0) 
    AND ([Project2].[C1] = 1)) AS [Distinct1]) 
    AS [C5] 
FROM (SELECT 
    @contactId AS [contactId], 
    @p__linq__0 AS [p__linq__0], 
    [GroupBy1].[K1] AS [C1], 
    [GroupBy1].[A1] AS [C2], 
    [GroupBy1].[A2] AS [C3], 
    [GroupBy1].[A3] AS [C4] 
FROM (SELECT 
    [Project1].[K1] AS [K1], 
    SUM([Project1].[A1]) AS [A1], 
    SUM([Project1].[A2]) AS [A2], 
    SUM([Project1].[A3]) AS [A3] 
FROM (SELECT 
    1 AS [K1], 
    [Project1].[JIMQuantityActual] * [Project1].[JIMNetMarginFactor] AS [A1], 
    [Project1].[CarbonSaving] AS [A2], 
    ([Project1].[MATRecoverablePercent]/CAST(100 AS DECIMAL(18))) * [Project1].[JIMQuantityActual] * [Project1].[JIMNetMarginFactor] AS [A3] 
FROM (SELECT 
    [Extent2].[MATRecoverablePercent] AS [MATRecoverablePercent], 
    [Extent2].[JIMQuantityActual] AS [JIMQuantityActual], 
    [Extent2].[JIMNetMarginFactor] AS [JIMNetMarginFactor], 
    [Extent2].[CarbonSaving] AS [CarbonSaving] 
FROM [dbo].[fn_GetJobsForUser](@contactId) AS [Extent1] 
INNER JOIN (SELECT 
    /*Fields omitted for brevity */ 
FROM [dbo].[cd_JobMaterial] AS [cd_JobMaterial]) AS [Extent2] 
    ON [Extent1].[JOBIDNumber] = [Extent2].[JIMJobId] 
WHERE [Extent1].[JOBCollectionDate] >= @p__linq__0) AS [Project1]) AS [Project1] 
GROUP BY [K1]) AS [GroupBy1]) AS [Project2]) AS [Project4] 

如何重寫linq表達式以產生更多的e不熟練的SQL,或者只是寫一個存儲過程並使用它而已?

回答

1

不幸的是,這是使用像支持各種複雜翻譯的實體框架一樣靈活的東西的缺點之一。它顯然帶來了其他方面的巨大利益,所以你必須平衡這些與性能方面。

即使您可以找到一種方法來重寫將生成更好的SQL 現在的的查詢,但未來版本中的底層提供者可能會發生更改。 您的應用程序在性能不再可接受之前儘可能長時間享受乾淨簡潔的代碼。如果EF在這一點上沒有削減它,那麼使用一些提供的鉤子來執行原始SQL,存儲過程等,這些將不那麼漂亮。