清理Entity Framework生成的大型SQL查询

时间:2015-09-02 18:50:03

标签: c# linq entity-framework

我正在检查我的SQL查询以查看它们是否可以进行优化,然后我发现了一个只包含很少逻辑的大量查询。

我理解查询的某些部分,但我不确定为什么每次都选择这么多列。

为什么实体框架如此分配/选择网站实体? (网站实体包含以下列:id,title,description)。

 FROM      (SELECT 
                    [Project4].[Id] AS [Id], 
                    [Project4].[Title] AS [Title], 
                    [Project4].[Description] AS [Description], 
                    [Project4].[Url] AS [Url], 
                    [Project4].[BannerURL] AS [BannerURL], 
                    [Project4].[UserID] AS [UserID], 
                    [Project4].[CategoryID] AS [CategoryID], 
                    [Project4].[Keywords] AS [Keywords], 
                    [Project4].[Enabled] AS [Enabled], 
                    [Project4].[DateAdded] AS [DateAdded], 
                    [Project4].[Sponsored] AS [Sponsored], 
                    [Project4].[ServerIP] AS [ServerIP], 
                    [Project4].[ServerPort] AS [ServerPort], 
                    [Project4].[MonitorCheckedDate] AS [MonitorCheckedDate], 
                    [Project4].[IsOnline] AS [IsOnline], 
                    [Project4].[BannerFileName] AS [BannerFileName], 
                    [Project4].[Thumbnail] AS [Thumbnail], 
                    [Project4].[C1] AS [C1], 
                    [Project4].[C2] AS [C2], 

完整的SQL查询:

SELECT TOP (25) 
    [Filter8].[Id1] AS [Id], 
    [Filter8].[Title] AS [Title], 
    [Filter8].[Description] AS [Description], 
    [Filter8].[Url] AS [Url], 
    [Filter8].[BannerURL] AS [BannerURL], 
    [Filter8].[UserID] AS [UserID], 
    [Filter8].[CategoryID] AS [CategoryID], 
    [Filter8].[Keywords] AS [Keywords], 
    [Filter8].[Enabled] AS [Enabled], 
    [Filter8].[DateAdded] AS [DateAdded], 
    [Filter8].[Sponsored] AS [Sponsored], 
    [Filter8].[ServerIP] AS [ServerIP], 
    [Filter8].[ServerPort] AS [ServerPort], 
    [Filter8].[MonitorCheckedDate] AS [MonitorCheckedDate], 
    [Filter8].[IsOnline] AS [IsOnline], 
    [Filter8].[BannerFileName] AS [BannerFileName], 
    [Filter8].[Thumbnail] AS [Thumbnail]

    // What's going on here?

    FROM ( SELECT [Filter7].[Id1], [Filter7].[Title], [Filter7].[Description], [Filter7].[Url], [Filter7].[BannerURL], [Filter7].[UserID], [Filter7].[CategoryID], [Filter7].[Keywords], [Filter7].[Enabled], [Filter7].[DateAdded], [Filter7].[Sponsored], [Filter7].[ServerIP], [Filter7].[ServerPort], [Filter7].[MonitorCheckedDate], [Filter7].[IsOnline], [Filter7].[BannerFileName], [Filter7].[Thumbnail], [Filter7].[C1], [Filter7].[C2], [Filter7].[C3], [Filter7].[IsAdminVerified1], [Filter7].[IsEmailVerified1], [Filter7].[BannedEndDate1], [Filter7].[BannedEndDate2], row_number() OVER (ORDER BY [Filter7].[Sponsored] DESC, [Filter7].[C2] DESC, [Filter7].[C3] DESC, [Filter7].[C1] DESC, [Filter7].[DateAdded] DESC) AS [row_number]
        FROM ( SELECT [Filter6].[Id1], [Filter6].[Title], [Filter6].[Description], [Filter6].[Url], [Filter6].[BannerURL], [Filter6].[UserID], [Filter6].[CategoryID], [Filter6].[Keywords], [Filter6].[Enabled], [Filter6].[DateAdded], [Filter6].[Sponsored], [Filter6].[ServerIP], [Filter6].[ServerPort], [Filter6].[MonitorCheckedDate], [Filter6].[IsOnline], [Filter6].[BannerFileName], [Filter6].[Thumbnail], [Filter6].[C1], [Filter6].[C2], [Filter6].[C3], [Filter6].[IsAdminVerified1], [Filter6].[IsEmailVerified1], [Filter6].[BannedEndDate1], [Filter6].[BannedEndDate2]
            FROM ( SELECT [Filter5].[Id1], [Filter5].[Title], [Filter5].[Description], [Filter5].[Url], [Filter5].[BannerURL], [Filter5].[UserID], [Filter5].[CategoryID], [Filter5].[Keywords], [Filter5].[Enabled], [Filter5].[DateAdded], [Filter5].[Sponsored], [Filter5].[ServerIP], [Filter5].[ServerPort], [Filter5].[MonitorCheckedDate], [Filter5].[IsOnline], [Filter5].[BannerFileName], [Filter5].[Thumbnail], [Filter5].[C1], [Filter5].[C2], [Filter5].[C3], [Filter5].[IsAdminVerified1], [Filter5].[IsEmailVerified1], [Filter5].[BannedEndDate1], [Filter5].[BannedEndDate2]
                FROM ( SELECT [Project5].[Id] AS [Id1], [Project5].[Title] AS [Title], [Project5].[Description] AS [Description], [Project5].[Url] AS [Url], [Project5].[BannerURL] AS [BannerURL], [Project5].[UserID] AS [UserID], [Project5].[CategoryID] AS [CategoryID], [Project5].[Keywords] AS [Keywords], [Project5].[Enabled] AS [Enabled], [Project5].[DateAdded] AS [DateAdded], [Project5].[Sponsored] AS [Sponsored], [Project5].[ServerIP] AS [ServerIP], [Project5].[ServerPort] AS [ServerPort], [Project5].[MonitorCheckedDate] AS [MonitorCheckedDate], [Project5].[IsOnline] AS [IsOnline], [Project5].[BannerFileName] AS [BannerFileName], [Project5].[Thumbnail] AS [Thumbnail], [Project5].[C1] AS [C1], [Project5].[C2] AS [C2], [Project5].[C3] AS [C3], [Extent6].[IsAdminVerified] AS [IsAdminVerified1], [Extent7].[IsEmailVerified] AS [IsEmailVerified1], [Extent8].[BannedEndDate] AS [BannedEndDate1], [Extent9].[BannedEndDate] AS [BannedEndDate2]

                    // Why the repeat?

                    FROM      (SELECT 
                        [Project4].[Id] AS [Id], 
                        [Project4].[Title] AS [Title], 
                        [Project4].[Description] AS [Description], 
                        [Project4].[Url] AS [Url], 
                        [Project4].[BannerURL] AS [BannerURL], 
                        [Project4].[UserID] AS [UserID], 
                        [Project4].[CategoryID] AS [CategoryID], 
                        [Project4].[Keywords] AS [Keywords], 
                        [Project4].[Enabled] AS [Enabled], 
                        [Project4].[DateAdded] AS [DateAdded], 
                        [Project4].[Sponsored] AS [Sponsored], 
                        [Project4].[ServerIP] AS [ServerIP], 
                        [Project4].[ServerPort] AS [ServerPort], 
                        [Project4].[MonitorCheckedDate] AS [MonitorCheckedDate], 
                        [Project4].[IsOnline] AS [IsOnline], 
                        [Project4].[BannerFileName] AS [BannerFileName], 
                        [Project4].[Thumbnail] AS [Thumbnail], 
                        [Project4].[C1] AS [C1], 
                        [Project4].[C2] AS [C2], 
                        (SELECT 
                            COUNT(1) AS [A1]
                            FROM [dbo].[WebsiteOut] AS [Extent5]
                            WHERE ([Project4].[Id] = [Extent5].[WebsiteID]) AND ([Extent5].[Unique] = 1)) AS [C3]
                        FROM ( SELECT 
                            [Project2].[Id] AS [Id], 
                            [Project2].[Title] AS [Title], 
                            [Project2].[Description] AS [Description], 
                            [Project2].[Url] AS [Url], 
                            [Project2].[BannerURL] AS [BannerURL], 
                            [Project2].[UserID] AS [UserID], 
                            [Project2].[CategoryID] AS [CategoryID], 
                            [Project2].[Keywords] AS [Keywords], 
                            [Project2].[Enabled] AS [Enabled], 
                            [Project2].[DateAdded] AS [DateAdded], 
                            [Project2].[Sponsored] AS [Sponsored], 
                            [Project2].[ServerIP] AS [ServerIP], 
                            [Project2].[ServerPort] AS [ServerPort], 
                            [Project2].[MonitorCheckedDate] AS [MonitorCheckedDate], 
                            [Project2].[IsOnline] AS [IsOnline], 
                            [Project2].[BannerFileName] AS [BannerFileName], 
                            [Project2].[Thumbnail] AS [Thumbnail], 
                            CASE WHEN ( EXISTS (SELECT 
                                1 AS [C1]
                                FROM [dbo].[WebsiteRating] AS [Extent4]
                                WHERE [Project2].[Id] = [Extent4].[WebsiteID]
                            )) THEN  CAST( [Project2].[C2] AS int) ELSE 5 END AS [C1], 
                            [Project2].[C1] AS [C2]
                            FROM ( SELECT 
                                [Project1].[Id] AS [Id], 
                                [Project1].[Title] AS [Title], 
                                [Project1].[Description] AS [Description], 
                                [Project1].[Url] AS [Url], 
                                [Project1].[BannerURL] AS [BannerURL], 
                                [Project1].[UserID] AS [UserID], 
                                [Project1].[CategoryID] AS [CategoryID], 
                                [Project1].[Keywords] AS [Keywords], 
                                [Project1].[Enabled] AS [Enabled], 
                                [Project1].[DateAdded] AS [DateAdded], 
                                [Project1].[Sponsored] AS [Sponsored], 
                                [Project1].[ServerIP] AS [ServerIP], 
                                [Project1].[ServerPort] AS [ServerPort], 
                                [Project1].[MonitorCheckedDate] AS [MonitorCheckedDate], 
                                [Project1].[IsOnline] AS [IsOnline], 
                                [Project1].[BannerFileName] AS [BannerFileName], 
                                [Project1].[Thumbnail] AS [Thumbnail], 
                                [Project1].[C1] AS [C1], 
                                (SELECT 
                                    AVG( CAST( [Extent3].[Rating] AS float)) AS [A1]
                                    FROM [dbo].[WebsiteRating] AS [Extent3]
                                    WHERE [Project1].[Id] = [Extent3].[WebsiteID]) AS [C2]
                                FROM ( SELECT 
                                    [Extent1].[Id] AS [Id], 
                                    [Extent1].[Title] AS [Title], 
                                    [Extent1].[Description] AS [Description], 
                                    [Extent1].[Url] AS [Url], 
                                    [Extent1].[BannerURL] AS [BannerURL], 
                                    [Extent1].[UserID] AS [UserID], 
                                    [Extent1].[CategoryID] AS [CategoryID], 
                                    [Extent1].[Keywords] AS [Keywords], 
                                    [Extent1].[Enabled] AS [Enabled], 
                                    [Extent1].[DateAdded] AS [DateAdded], 
                                    [Extent1].[Sponsored] AS [Sponsored], 
                                    [Extent1].[ServerIP] AS [ServerIP], 
                                    [Extent1].[ServerPort] AS [ServerPort], 
                                    [Extent1].[MonitorCheckedDate] AS [MonitorCheckedDate], 
                                    [Extent1].[IsOnline] AS [IsOnline], 
                                    [Extent1].[BannerFileName] AS [BannerFileName], 
                                    [Extent1].[Thumbnail] AS [Thumbnail], 
                                    (SELECT 
                                        COUNT(1) AS [A1]
                                        FROM [dbo].[WebsiteIn] AS [Extent2]
                                        WHERE ([Extent1].[Id] = [Extent2].[WebsiteID]) AND ([Extent2].[Unique] = 1)) AS [C1]
                                    FROM [dbo].[Websites] AS [Extent1]
                                )  AS [Project1]
                            )  AS [Project2]
                        )  AS [Project4] ) AS [Project5]
                    INNER JOIN [dbo].[Users] AS [Extent6] ON [Project5].[UserID] = [Extent6].[Id]
                    INNER JOIN [dbo].[Users] AS [Extent7] ON [Project5].[UserID] = [Extent7].[Id]
                    LEFT OUTER JOIN [dbo].[Users] AS [Extent8] ON [Project5].[UserID] = [Extent8].[Id]
                    LEFT OUTER JOIN [dbo].[Users] AS [Extent9] ON [Project5].[UserID] = [Extent9].[Id]
                    WHERE [Project5].[Enabled] = 1
                )  AS [Filter5]
                WHERE [Filter5].[IsAdminVerified1] = 1
            )  AS [Filter6]
            WHERE [Filter6].[IsEmailVerified1] = 1
        )  AS [Filter7]
        WHERE ([Filter7].[BannedEndDate1] IS NULL) OR ( CAST( SysDateTime() AS datetime2) > [Filter7].[BannedEndDate2])
    )  AS [Filter8]
    WHERE [Filter8].[row_number] > 0
    ORDER BY [Filter8].[Sponsored] DESC, [Filter8].[C2] DESC, [Filter8].[C3] DESC, [Filter8].[C1] DESC, [Filter8].[DateAdded] DESC

的LINQ:

(from website in _unitOfWorkRepository.WebsitesRepository.GetAll()
               let amountVotes = website.WebsiteIn.Count(x => x.Unique)
               let ratings = website.WebsiteRating.Select(x => x.Rating)
               let avgRate = ratings.Any() ? (int)ratings.Average() : 5
               let amountRedirects = website.WebsiteOut.Count(x => x.Unique)
               where
                   website.Enabled && website.Users.IsAdminVerified && website.Users.IsEmailVerified &&
                   (website.Users.BannedEndDate == null || DateTime.Now > website.Users.BannedEndDate)
               orderby website.Sponsored descending,
                   amountVotes descending,
                   amountRedirects descending,
                   avgRate descending,
                   website.DateAdded descending
               select website);

数据库逻辑:

  • 用户 - > (多个)网站 - > WebsiteIn& WebsiteRating& WebsiteIn& WebsiteOut

1 个答案:

答案 0 :(得分:3)

  

我发现了一个只包含很少逻辑的大量查询。

完全没有,它包含 lot 的逻辑:

  • 4 let个语句,每个语句都会导致聚合子查询。
  • 使用orderby语句
  • 结果的4 let个子句

要使SQL语句能够按子查询结果排序,它应该嵌套SELECT语句。如果没有嵌套,则需要在ORDER BY短语中重复聚合查询。不管你信不信,这已经是一种有点优化的查询形式。

  

为什么选择这么多列

最终结果是完整Website个对象的列表,因此相应表中的所有列都应出现在结果集中。这些列最终来自最内部的查询。

所以那里没有太多可以轻松优化的东西,尤其是。不是由查询生成器。

如果查询导致您在性能方面遇到麻烦,您可以考虑

  1. 返回一个投影,即返回列的子集(即:不是Website个对象,而是属性较少的类型。)
  2. 在没有排序的情况下,以包含聚合数字的类型返回结果,并在内存中进行排序。这将使查询形状变得扁平化,并从查询优化器中省去一些工作。