为什么此 Microsoft SQL Server 查询中的排序成本为 94%?

问题描述 投票:0回答:1

我的 Linq to SQL 查询速度很慢(2 秒返回 1000 行)

var listReceptacle = await((STTEntities)_unitOfWork.Context).IRTReceptacles
            .Include(r => r.Product)
            .Include(r => r.IRTEvents)
            .Where(r =>  r.IRTEvents.OrderByDescending(re => re.Timestamp)
            .Take(1)
            .Any(re => re.IRTEventTypeId == IRTEventType.InternalReceptacleCreated.Id
                    || re.IRTEventTypeId == IRTEventType.InternalReceptacleReOpened.Id
                    || re.IRTEventTypeId == IRTEventType.InternalReceptacleClosed.Id
                    || re.IRTEventTypeId == IRTEventType.InternalReceptacleIsPendingDispatch.Id
                )
            )
            .ToListAsync();

表格如下。

  1. 有一个容器
  2. 可以有一个或多个与其关联的事件(例如容器创建、容器关闭、容器调度、交付等)
  3. 有一个事件类型表(事件类型少于20种)
  4. 添加一个容器可以与一个产品相关联。

表在这些列上有索引

插座

   ID 
   Barcode

活动

   ID
   EventTypeID
   ReceptacleID
   Timestamp

事件类型

   ID
   Code - must be unique

粘贴箱中的实际执行计划:https://www.brentozar.com/pastetheplan/?id=H1dRIdkN6

SQL 查询的实际执行计划显示排序块的成本为 94%。

这是实际执行计划的摘录(我已将整个计划粘贴在底部)

将鼠标悬停在排序块上会显示

我在事件表中添加了以下索引,但排序块仍然有 94% 的成本。

  1. EventTypeId + Timestamp 列上的复合索引
  2. 列 Id + Timestamp 的复合索引
  3. 包含 EventTypeId 列的时间戳索引

代码:

CREATE NONCLUSTERED INDEX [IX_IRTEvents_IRTEventTypeId_TimeStamp] 
ON [dbo].[IRTEvents] ([IRTEventTypeId] ASC, [TimeStamp] ASC)

CREATE NONCLUSTERED INDEX [IX_IRTEvents_Id_TimeStamp] 
ON [dbo].[IRTEvents] ([Id] ASC, [TimeStamp] ASC)

CREATE NONCLUSTERED INDEX [IX_IRTEvents_TimeStamp_2] 
ON [dbo].[IRTEvents] ([TimeStamp] DESC)
INCLUDE (IRTEventTypeId)

这是查询(由 Linq 生成)

USE SwiftTrackAndTrace
DECLARE @p__linq__0 INT = 1 
DECLARE @p__linq__1 INT = 3 
DECLARE @p__linq__2 INT = 2 
DECLARE @p__linq__3 INT = 6 
SELECT
        [Project3].[Id]                        AS [Id]                       ,
        [Project3].[Barcode]                   AS [Barcode]                  ,
        [Project3].[AllowedProductId]          AS [AllowedProductId]         ,
        [Project3].[DestinationLocationId]     AS [DestinationLocationId]    ,
        [Project3].[Id1]                       AS [Id1]                      ,
        [Project3].[ProductGroupId]            AS [ProductGroupId]           ,
        [Project3].[Code]                      AS [Code]                     ,
        [Project3].[Description]               AS [Description]              ,
        [Project3].[Rowversion]                AS [Rowversion]               ,
        [Project3].[ValidateCheckDigit]        AS [ValidateCheckDigit]       ,
        [Project3].[AllowCustom]                AS [AllowCustom]  ,
        [Project3].[ImportInfo]                 AS [ImportInfo],
        [Project3].[NewItem]                   AS [NewItem]    ,
        [Project3].[IsActive]                  AS [IsActive]                 ,
        [Project3].[C1]                        AS [C1]                       ,
        [Project3].[Id2]                       AS [Id2]                      ,
        [Project3].[IRTReceptacleId]           AS [IRTReceptacleId]          ,
        [Project3].[IRTEventTypeId]            AS [IRTEventTypeId]           ,
        [Project3].[TIMESTAMP]                 AS [TIMESTAMP]                ,
        [Project3].[LocationId]                AS [LocationId]               
        --[Project3].[UserId]                    AS [UserId]
FROM
        (
                SELECT
                        [Extent1].[Id]                                                       AS [Id]                       ,
                        [Extent1].[Barcode]                                                  AS [Barcode]                  ,
                        [Extent1].[AllowedProductId]                                         AS [AllowedProductId]         ,
                        [Extent1].[DestinationLocationId]                                    AS [DestinationLocationId]    ,
                        [Extent2].[Id]                                                       AS [Id1]                      ,
                        [Extent2].[ProductGroupId]                                           AS [ProductGroupId]           ,
                        [Extent2].[Code]                                                     AS [Code]                     ,
                        [Extent2].[Description]                                              AS [Description]              ,
                        [Extent2].[Rowversion]                                               AS [Rowversion]               ,
                        [Extent2].[ValidateCheckDigit]                                       AS [ValidateCheckDigit]       ,
                        [Extent2].[AllowCustom]                                             AS [AllowCustom]  ,
                        [Extent2].[ImportInfo]                                              AS [ImportInfo],
                        [Extent2].[NewItem]                                                 AS [NewItem]    ,
                        [Extent2].[IsActive]                                                 AS [IsActive]                 ,
                        [Extent3].[Id]                                                       AS [Id2]                      ,
                        [Extent3].[IRTReceptacleId]                                          AS [IRTReceptacleId]          ,
                        [Extent3].[IRTEventTypeId]                                           AS [IRTEventTypeId]           ,
                        [Extent3].[TIMESTAMP]                                                AS [TIMESTAMP]                ,
                        [Extent3].[LocationId]                                               AS [LocationId]               ,
                        --[Extent3].[UserId]                                                   AS [UserId]                   
                        CASE WHEN ([Extent3].[Id] IS NULL) THEN CAST(NULL AS INT) ELSE 1 END AS [C1]
                FROM
                        [dbo].[IRTReceptacles] AS [Extent1]
                LEFT OUTER JOIN
                        [dbo].[Products] AS [Extent2]
                ON
                        [Extent1].[AllowedProductId] = [Extent2].[Id]
                LEFT OUTER JOIN
                        [dbo].[IRTEvents] AS [Extent3]
                ON
                        [Extent1].[Id] = [Extent3].[IRTReceptacleId]
                WHERE
                        EXISTS
                        (
                                SELECT
                                        1 AS [C1]
                                FROM
                                        (
                                                SELECT
                                                        TOP (1) [Project1].[IRTEventTypeId] AS [IRTEventTypeId]
                                                FROM
                                                        (
                                                                SELECT
                                                                        [Extent4].[IRTEventTypeId] AS [IRTEventTypeId],
                                                                        [Extent4].[TIMESTAMP]      AS [TIMESTAMP]
                                                                FROM
                                                                        [dbo].[IRTEvents] AS [Extent4]
                                                                WHERE
                                                                        [Extent1].[Id] = [Extent4].[IRTReceptacleId] ) AS [Project1]
                                                ORDER BY
                                                        [Project1].[TIMESTAMP] DESC ) AS [Limit1]
                                WHERE
                                        [Limit1].[IRTEventTypeId] IN (@p__linq__0,
                                                                      @p__linq__1,
                                                                      @p__linq__2,
                                                                      @p__linq__3) ) ) AS [Project3]
ORDER BY
        [Project3].[Id] ASC ,
        [Project3].[Id1] ASC,
        [Project3].[C1] ASC 

sql-server linq-to-sql query-optimization
1个回答
0
投票

你最好使用

JOIN
而不是那个复杂的
any
条件:

  • 首先,从按 IRTReceptacleId 分组的 IRTEvent 创建可查询对象,然后选择 IRTReceptacleId 和 max(Timestamp)。
  • 然后,
    JOIN
    可查询 IRTReceptacle(在 IRTReceptacleId 上)和 IRTEvent(在 IRTReceptacleId 和 Timestamp 上)以检查 IRTEventTypeId 上的条件。
© www.soinside.com 2019 - 2024. All rights reserved.