2013-12-14 30 views
1

我有一個數據庫結構如下的EntityFramework生成TSQL差(linqpad產生好得多)

家庭(1) - - - - (*)FamilyPersons - - - - (1)人(1) ------()費用(1)-----(0..1)雜貨詳情

讓我解釋一下關係,家庭可以有一個或多個人,我們有一個映射表家庭人與人之間的家庭人。現在每個人都可以輸入他的費用,進入費用表。費用表有一列ExpenseType(雜貨,娛樂等) 和每個這些費用的細節進入他們自己的表,所以我們有一個GroceriesDetails表(同樣我們有其他表),所以我們有1到0..1的關係費用和雜貨之間。

現在我正在寫一個查詢,以獲得完整的GroceriesDetails爲家庭

GroceriesDetails.Where (g => g.Expenses.Person.FamilyPersons.Any(fp => 
fp.FamilyId == 1) && g.Expenses.ExpenseType == "GC") 

對於這個由EF生成的SQL是

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Amount] AS [Amount] 
FROM [dbo].[GroceriesDetails] AS [Extent1] 
INNER JOIN (SELECT [Extent3].[Id] AS [Id1] 
    FROM [dbo].[Expenses] AS [Extent2] 
    INNER JOIN [dbo].[GroceriesDetails] AS [Extent3] ON [Extent2].[Id] = [Extent3].[Id] 
    WHERE N'GC' = [Extent2].[ExpenseType]) AS [Filter1] ON [Extent1].[Id] = [Filter1].[Id1] 
WHERE EXISTS (SELECT 
    1 AS [C1] 
    FROM [dbo].[Expenses] AS [Extent4] 
    INNER JOIN [dbo].[GroceriesDetails] AS [Extent5] ON [Extent4].[Id] = [Extent5].[Id] 
    INNER JOIN [dbo].[FamilyPerson] AS [Extent6] ON [Extent4].[PersonId] = [Extent6].[PersonId] 
    WHERE ([Extent1].[Id] = [Extent5].[Id]) AND (1 = [Extent6].[FamilyId]) 
) 

在此查詢有一個全表費用之間的連接和導致性能問題的GroceriesDetails表。

而Linqpad產生一個更好的SQL

SELECT [t0].[Id], [t0].[Amount] 
FROM [GroceriesDetails] AS [t0] 
INNER JOIN [Expenses] AS [t1] ON [t1].[Id] = [t0].[Id] 
WHERE (EXISTS(
    SELECT NULL AS [EMPTY] 
    FROM [Expenses] AS [t2] 
    INNER JOIN [Person] AS [t3] ON [t3].[Id] = [t2].[PersonId] 
    CROSS JOIN [FamilyPerson] AS [t4] 
    WHERE ([t4].[FamilyId] = @p0) AND ([t2].[Id] = [t0].[Id]) AND ([t4].[PersonId] = 
[t3].[Id]) 
    )) AND ([t1].[ExpenseType] = @p1) 

請注意,我們使用WCF數據服務,使該查詢針對WCF數據服務引用寫的,所以我不能穿越從頂部(系列)到底(雜貨),因爲OData只允許一級選擇。

任何有關優化此代碼的幫助表示讚賞。

+0

AFAIK LinqPad本身不會產生任何查詢,它只是讓EF做到這一點。您確定在LinqPad和您的應用程序中運行查詢時使用相同的EF嗎?你確定查詢是完全一樣的,你的應用程序沒有做任何事情(添加更多的ctiteria等)? –

+0

@AlexeyRaga在LinqPad中,我使用Linq 2 Sql進行ORM,在我的應用程序中使用Entity-Framework,並且在兩種情況下它都是相同的查詢。 –

回答

3

從評論中我瞭解到,LinqPad在應用程序使用EF時使用Linq2SQL,並解釋了差異。

問題是,您對EF如何生成SQL沒有控制權。 你可以做的唯一事情就是重寫你的LINQ查詢,使其「更接近」所需的SQL。

例如,而不是

GroceriesDetails.Where (g => g.Expenses.Person.FamilyPersons.Any(fp => fp.FamilyId == 1) 
          && g.Expenses.ExpenseType == "GC") 

你可以嘗試寫類似(僞):

from g in GrosseriesDetails 
join e in Expenses on g.Id = e.GrosseryId 
join p in Persons on p.Id = e.PersonId 
join f in FamilyPersons on f.PersonId = p.Id 
where f.FamilyId == 1 && e.ExpenseType == "GC" 

它幾乎總是有幫助,因爲它講述了一個ORM一個簡單的方法將它轉變成SQL。這個想法是,「原始」情況下的表達式樹比提議的場景更復雜,通過簡化表達式樹,我們使翻譯器的工作變得更簡單,更直接。

但除了操縱LINQ之外,還無法控制它如何從表達式樹生成SQL。

+0

我使用不允許連接的WCF數據服務。 –