查询更改速度(34 vs 0秒),没有执行计划缓存(从EF Core生成的SQL)没有数据/模式更改]]

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

我有一个相当大的查询,该查询在数据很少的数据库上运行非常慢(此查询访问的表的最高行数是8K,并且大多数过滤器都在具有EF导航属性的ID上,这是唯一的参数通过的是一个GUID。

它运行起来像丝般顺滑,但经过一些更改(很遗憾,我们今天更改了一个“批次”,以将其重新处理为一个查询,而在cshtml中它超过30并进行了延迟加载,现在都已在文件开头预加载了所有内容) ),它现在以蜗牛般的速度运行(超时时间为30秒,耗时34秒)。在SQL Server Management Studio中运行它可以提供相同的运行时间(34秒),多次执行并不能加快运行速度,显示执行计划,稍等片刻,然后再次运行,有时它从34变为0秒。

我们排除了以下内容:

  • 查询计划执行缓存(How can I clear the SQL Server query cache?):刷新计划后,执行时间不会改变,一旦速度很快,它将保持很快

  • 结果未缓存:更改guid(更改其他所有值)不会更改任何内容,一旦运行速度很快,它将保持快速运行

  • ] >>
  • SQL Server安装问题:当这发生在我同事的PC上时,我获取了最新版本并重现了同一问题

  • 与计算机有关的问题:除了SQL Server外,没有占用CPU时间的东西,没有其他打开的设备,两台计算机都运行良好并且没有关联(不在同一网络上/不在域中,等等),这会影响它们都可以排除同时出现的负面影响。

  • 我们无所适从,因为调试“为什么”真的很困难,因为当它最终突然无所事事地开始执行时,它起步很慢。

    我不确定查询是否有用,因此为什么我最后发布它,我重命名了一些表(来自T0 T1等),以使其更易于阅读,但很难理解。您会发现下面的信息既是用于生成它的C#代码,又是一次又一次的SQL结果,历时34秒,直到花费0!]

LINQ(最新发布的ef core,3.1):

Context.Orders
    .Where(o => o.UniqueId == new Guid("MY GUID HERE"))
    .SelectMany(o => o.Products)
    .Where(FranceMontgolfieres.Models.Mappings.ProductOrder.IsTicketExpression)
    .Select(po => new
    {
        po.UniqueId,
        ProductId = po.Product.Id,
        ProductName = po.Product.Name,
        AllPassengerAreRegistered = po.Passengers.All(pa => pa.Passenger != null),
        passengers = po.Passengers
                .Select(pa => new
                {
                    pa.UniqueId,
                    IsRegistered = pa.Passenger != null,
                    pa.Passenger.FirstName,
                    pa.Passenger.LastName,
                    FullName = pa.Passenger.FirstName + " " + pa.Passenger.LastName,
                    HasFlown = pa.Passenger.Manifests
                    .Any(m => m.History
                        .Any(h => h.Status == PassengerManifestStatus.Flown)),
                    HasPendingFlight = pa.Passenger.Manifests
                    .Any(m => m.History
                        .Any(h => h.Status == PassengerManifestStatus.Incoming)),
                    HasPendingReport = pa.Passenger.Manifests
                    .Any(m => m.History
                        .Any(h => h.Status == PassengerManifestStatus.Report)),
                    Manifests = pa.Passenger.Manifests
                        .Select(m => new
                        {
                            manifest = new
                            {
                                HasFlown = m.History
                                    .Any(h => h.Status == PassengerManifestStatus.Flown),
                                HasPendingFlight = m.History
                                    .Any(h => h.Status == PassengerManifestStatus.Incoming),
                                HasPendingReport = m.History
                                    .Any(h => h.Status == PassengerManifestStatus.Report),
                                m.Manifest.StartDate,
                                m.Manifest.FlightBase.Name,
                                m.Manifest.FlightBase.Location,
                                m.Manifest.State
                            },
                            history = m.History
                                .Select(h => new
                                {
                                    h.Date,
                                    h.Status
                                })
                        })
                }),
        PendingReservationExists = po.PendingReservation != null
    })
    .ToList();

我们在查询之前运行的内容(仍然需要0秒的时间,以确保它不会被缓存:

CHECKPOINT; 
GO 
DBCC DROPCLEANBUFFERS; 
GO
DBCC FREEPROCCACHE;
GO
DBCC FREESYSTEMCACHE("ALL");
GO
DBCC FREESESSIONCACHE;
GO
DBCC FLUSHAUTHCACHE;
GO

SQL查询:

SELECT [ProductOrders_p1].[UniqueId],
    [Products_p2].[Id], 
    [TranslatableString_t].[Id], 
    [TranslatableString_t].[MainPageCompanyDetailId], 
    [TranslatableString_t].[Text], 
    CASE
          WHEN NOT EXISTS (
              SELECT 1
              FROM [ProductOrderPassenger] AS [p]
              LEFT JOIN [Passengers] AS [p0] ON [p].[Id] = [p0].[ProductOrderPassengerId]
              WHERE ([ProductOrders_p1].[Id] = [p].[ProductOrderId]) AND [p0].[Id] IS NULL) THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END,
    CASE
          WHEN [PendingReservations_p3].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END, 
    [o].[Id], 
    [ProductOrders_p1].[Id], 
    [t3].[UniqueId], 
    [t3].[c], 
    [t3].[FirstName], 
    [t3].[LastName], 
    [t3].[c0], 
    [t3].[c1], 
    [t3].[c2],
    [t3].[c3], 
    [t3].[Id], 
    [t3].[c4], 
    [t3].[c00], 
    [t3].[c10],
    [t3].[StartDate], 
    [t3].[Id0], 
    [t3].[MainPageCompanyDetailId], 
    [t3].[Text], 
    [t3].[Id00], 
    [t3].[MainPageCompanyDetailId0], 
    [t3].[Text0], 
    [t3].[State], 
    [t3].[ManifestId], 
    [t3].[PassengerId], 
    [t3].[Id1], 
    [t3].[Date],
    [t3].[Status], 
    [t3].[Id2]
      FROM [Orders] AS [o]
      INNER JOIN [ProductOrders] AS [ProductOrders_p1] ON [o].[Id] = [ProductOrders_p1].[OrderId]
      LEFT JOIN [Products] AS [Products_p2] ON [ProductOrders_p1].[ProductId] = [Products_p2].[Id]
      LEFT JOIN [TranslatableStrings] AS [TranslatableString_t] ON [Products_p2].[NameId] = [TranslatableString_t].[Id]
      LEFT JOIN [PendingReservations] AS [PendingReservations_p3] ON [ProductOrders_p1].[Id] = [PendingReservations_p3].[ProductOrderId]
      LEFT JOIN (
          SELECT [ProductOrderPassengers_p4].[UniqueId], CASE
              WHEN [Passengers_p5].[Id] IS NOT NULL THEN CAST(1 AS bit)
              ELSE CAST(0 AS bit)
          END AS [c], [Passengers_p5].[FirstName], [Passengers_p5].[LastName], ([Passengers_p5].[FirstName] + N' ') + [Passengers_p5].[LastName] AS [c0], CASE
              WHEN EXISTS (
                  SELECT 1
                  FROM [ManifestPassengers] AS [m]
                  WHERE ([Passengers_p5].[Id] IS NOT NULL AND ([Passengers_p5].[Id] = [m].[PassengerId])) AND EXISTS (
                      SELECT 1
                      FROM [ManifestPassengerHistories] AS [m0]
                      WHERE (([m].[ManifestId] = [m0].[ManifestPassengerManifestId]) AND ([m].[PassengerId] = [m0].[ManifestPassengerPassengerId])) AND ([m0].[Status] = 5))) THEN CAST(1 AS bit)
              ELSE CAST(0 AS bit)
          END AS [c1], CASE
              WHEN EXISTS (
                  SELECT 1
                  FROM [ManifestPassengers] AS [m1]
                  WHERE ([Passengers_p5].[Id] IS NOT NULL AND ([Passengers_p5].[Id] = [m1].[PassengerId])) AND EXISTS (
                      SELECT 1
                      FROM [ManifestPassengerHistories] AS [m2]
                      WHERE (([m1].[ManifestId] = [m2].[ManifestPassengerManifestId]) AND ([m1].[PassengerId] = [m2].[ManifestPassengerPassengerId])) AND ([m2].[Status] = 1))) THEN CAST(1 AS bit)
              ELSE CAST(0 AS bit)
          END AS [c2], CASE
              WHEN EXISTS (
                  SELECT 1
                  FROM [ManifestPassengers] AS [m3]
                  WHERE ([Passengers_p5].[Id] IS NOT NULL AND ([Passengers_p5].[Id] = [m3].[PassengerId])) AND EXISTS (
                      SELECT 1
                      FROM [ManifestPassengerHistories] AS [m4]
                      WHERE (([m3].[ManifestId] = [m4].[ManifestPassengerManifestId]) AND ([m3].[PassengerId] = [m4].[ManifestPassengerPassengerId])) AND ([m4].[Status] = 2))) THEN CAST(1 AS bit)
              ELSE CAST(0 AS bit)
          END AS [c3], [ProductOrderPassengers_p4].[Id], [t2].[c] AS [c4], [t2].[c0] AS [c00], [t2].[c1] AS [c10], [t2].[StartDate], [t2].[Id] AS [Id0], [t2].[MainPageCompanyDetailId], [t2].[Text], [t2].[Id0] AS [Id00], [t2].[MainPageCompanyDetailId0], [t2].[Text0], [t2].[State], [t2].[ManifestId], [t2].[PassengerId], [t2].[Id1], [t2].[Date], [t2].[Status], [t2].[Id2], [ProductOrderPassengers_p4].[ProductOrderId]
          FROM [ProductOrderPassenger] AS [ProductOrderPassengers_p4]
          LEFT JOIN [Passengers] AS [Passengers_p5] ON [ProductOrderPassengers_p4].[Id] = [Passengers_p5].[ProductOrderPassengerId]
          LEFT JOIN (
              SELECT CASE
                  WHEN EXISTS (
                      SELECT 1
                      FROM [ManifestPassengerHistories] AS [m5]
                      WHERE (([m8].[ManifestId] = [m5].[ManifestPassengerManifestId]) AND ([m8].[PassengerId] = [m5].[ManifestPassengerPassengerId])) AND ([m5].[Status] = 5)) THEN CAST(1 AS bit)
                  ELSE CAST(0 AS bit)
              END AS [c], CASE
                  WHEN EXISTS (
                      SELECT 1
                      FROM [ManifestPassengerHistories] AS [m6]
                      WHERE (([m8].[ManifestId] = [m6].[ManifestPassengerManifestId]) AND ([m8].[PassengerId] = [m6].[ManifestPassengerPassengerId])) AND ([m6].[Status] = 1)) THEN CAST(1 AS bit)
                  ELSE CAST(0 AS bit)
              END AS [c0], CASE
                  WHEN EXISTS (
                      SELECT 1
                      FROM [ManifestPassengerHistories] AS [m7]
                      WHERE (([m8].[ManifestId] = [m7].[ManifestPassengerManifestId]) AND ([m8].[PassengerId] = [m7].[ManifestPassengerPassengerId])) AND ([m7].[Status] = 2)) THEN CAST(1 AS bit)
                  ELSE CAST(0 AS bit)
              END AS [c1], [m9].[StartDate], [t0].[Id], [t0].[MainPageCompanyDetailId], [t0].[Text], [t1].[Id] AS [Id0], [t1].[MainPageCompanyDetailId] AS [MainPageCompanyDetailId0], [t1].[Text] AS [Text0], [m9].[State], [m8].[ManifestId], [m8].[PassengerId], [m9].[Id] AS [Id1], [m10].[Date], [m10].[Status], [m10].[Id] AS [Id2]
              FROM [ManifestPassengers] AS [m8]
              INNER JOIN [Manifests] AS [m9] ON [m8].[ManifestId] = [m9].[Id]
              LEFT JOIN [FlightBases] AS [f] ON [m9].[FlightBaseId] = [f].[Id]
              LEFT JOIN [TranslatableStrings] AS [t0] ON [f].[NameId] = [t0].[Id]
              LEFT JOIN [TranslatableStrings] AS [t1] ON [f].[LocationId] = [t1].[Id]
              LEFT JOIN [ManifestPassengerHistories] AS [m10] ON ([m8].[ManifestId] = [m10].[ManifestPassengerManifestId]) AND ([m8].[PassengerId] = [m10].[ManifestPassengerPassengerId])
          ) AS [t2] ON [Passengers_p5].[Id] = [t2].[PassengerId]
      ) AS [t3] ON [ProductOrders_p1].[Id] = [t3].[ProductOrderId]
      WHERE ([o].[UniqueId] = 'd26013b9-b9bc-4497-b351-544739851d3d') AND EXISTS (
          SELECT 1
          FROM [ProductProductComponents] AS [p6]
          INNER JOIN (
              SELECT [p7].[Id], [p7].[DescriptionId], [p7].[Discriminator], [p7].[DisplayDescriptionInProduct], [p7].[FunctionnalName], [p7].[HTPrice], [p7].[IsArchived], [p7].[IsChildrenPrice], [p7].[IsOptionnal], [p7].[IsSelectedInBasketByDefault], [p7].[IsShipping], [p7].[NameId], [p7].[ParentProductComponentId], [p7].[ShowInBasket], [p7].[ShowInInvoice], [p7].[VATRate], [p7].[AllowPartnerBase], [p7].[AllowWeekends], [p7].[ValidForTicks]
              FROM [ProductComponents] AS [p7]
              WHERE [p7].[Discriminator] IN (N'ProductComponent', N'FlightProductComponent')
          ) AS [t4] ON [p6].[ProductComponentId] = [t4].[Id]
          WHERE ([Products_p2].[Id] IS NOT NULL AND ([Products_p2].[Id] = [p6].[ProductId])) AND ([t4].[Discriminator] = N'FlightProductComponent'))
      ORDER BY [o].[Id], [ProductOrders_p1].[Id], [t3].[Id], [t3].[ManifestId], [t3].[PassengerId], [t3].[Id1], [t3].[Id2]

我有一个相当大的查询,它在数据很少的数据库上运行非常慢(此查询访问的表的最高行数是8K,并且大多数过滤器都使用EF的ID ...

] >

是否可以考虑将查询放入存储过程?它应该与您为参数插入新值时保持相同的计划。或者,您可以尝试刷新统计信息并检查基于UniqueID的索引碎片。得出错误的估计值可能会导致制定错误的计划。

如果我不得不猜测,主要的索引点是订单,产品订单,乘客,并且在乘客和ProductOrderPassengers之间的左连接处,如果桌子的订单被翻转,就会有些奇怪。如果您必须保持临时状态,可以尝试的技巧是

声明@Oid varchar(10)设置@Oid =从订单中选择ID,其中UniqueID ='d26013b9-b9bc-4497-b351-544739851d3d'

然后,如果有1行有助于估算,则为该ID添加一个where子句。

如果它与许多ID一样是1个uniqueID,则可以将它们拉到临时表,然后将其加入。我知道这些事情有助于控制我们的错误估计,但是通常我们只尝试对存储的procs使用临时查询和复杂查询。

我不认为刷新缓存对您有任何帮助。

sql-server entity-framework entity-framework-core sql-server-2016 sql-execution-plan
1个回答
0
投票

是否可以考虑将查询放入存储过程?它应该与您为参数插入新值时保持相同的计划。或者,您可以尝试刷新统计信息并检查基于UniqueID的索引碎片。得出错误的估计值可能会导致制定错误的计划。

© www.soinside.com 2019 - 2024. All rights reserved.