是否可以考虑将查询放入存储过程?它应该与您为参数插入新值时保持相同的计划。或者,您可以尝试刷新统计信息并检查基于UniqueID的索引碎片。得出错误的估计值可能会导致制定错误的计划。
我有一个相当大的查询,该查询在数据很少的数据库上运行非常慢(此查询访问的表的最高行数是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使用临时查询和复杂查询。
我不认为刷新缓存对您有任何帮助。
是否可以考虑将查询放入存储过程?它应该与您为参数插入新值时保持相同的计划。或者,您可以尝试刷新统计信息并检查基于UniqueID的索引碎片。得出错误的估计值可能会导致制定错误的计划。