簡體   English   中英

改善LINQ到EF生成的SQL查詢

[英]Improving SQL query generated by LINQ to EF

我有一個學生表,我想編寫一個Linq查詢來獲取多個計數。 Linq生成的SQL查詢過於復雜且未經優化。

以下是我的表的定義:

[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NULL,
[Age] [int] NULL,

我需要對名稱為test的學生進行一次計數,對年齡大於10的學生進行一次計數。這是我嘗試過的查詢之一:

 var sql = from st in school.Students
                          group st by 1 into grp
                          select new
                          {
                              NameCount = grp.Count(k => k.Name == "Test"),
                              AgeCount = grp.Count(k => k.Age > 5)
                          };

生成的SQL查詢為:

SELECT 
    [Limit1].[C1] AS [C1], 
    [Limit1].[C2] AS [C2], 
    [Limit1].[C3] AS [C3]
    FROM ( SELECT TOP (1) 
        [Project2].[C1] AS [C1], 
        [Project2].[C2] AS [C2], 
        (SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent3]
            WHERE ([Project2].[C1] = 1) AND ([Extent3].[Age] > 5)) AS [C3]
        FROM ( SELECT 
            [Distinct1].[C1] AS [C1], 
            (SELECT 
                COUNT(1) AS [A1]
                FROM [dbo].[Student] AS [Extent2]
                WHERE ([Distinct1].[C1] = 1) AND (N'Test' = [Extent2].[Name])) AS [C2]
            FROM ( SELECT DISTINCT 
                1 AS [C1]
                FROM [dbo].[Student] AS [Extent1]
            )  AS [Distinct1]
        )  AS [Project2]
    )  AS [Limit1]

對我來說,這似乎很復雜。 可以通過以下簡單查詢來實現:

select COUNT(CASE WHEN st.Name = 'Test' THEN 1 ELSE 0 END) NameCount,
 COUNT(CASE WHEN st.Age > 5 THEN 1 ELSE 0 END) AgeCount from Student st

LINQ中是否有一種方法可以使生成的SQL查詢既具有聚合功能,又可以使兩個獨立的查詢與嵌套查詢結合在一起?

從我的經驗EF6,有條件的Sum (即Sum(condition ? 1 : 0)被翻譯要好得多SQL比Count謂語(即Count(condition) ):

var query =
    from st in school.Students
    group st by 1 into grp
    select new
    {
        NameCount = grp.Sum(k => k.Name == "Test" ? 1 : 0),
        AgeCount = grp.Sum(k => k.Age > 5 ? 1 : 0)
    };

順便說一句,您的SQL示例也應該使用SUM 為了利用排除NULL的SQL COUNT ,它應該是ELSE NULL或沒有ELSE

select COUNT(CASE WHEN st.Name = 'Test' THEN 1 END) NameCount,
    COUNT(CASE WHEN st.Age > 5 THEN 1 END) AgeCount
    from Student st

但是,對此沒有等效的LINQ構造,因此沒有辦法讓EF6生成這種轉換。 但是IMO的SUM就足夠了。

一個簡單得多的查詢是由於不使用不必要的group by,而只是在select查詢了兩次表:

var sql = from st in school.Students.Take(1)
          select new {
              NameCount = school.Students.Count(k => k.Name == "Test"),
              AgeCount = school.Students.Count(k => k.Age > 5)
          };

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM