Mik*_*keH 5 performance sql-server entity-framework sql-server-2017 query-performance
我每 1 秒执行一次查询,大部分时间它不返回任何结果(由实体框架生成的 SQL):
SELECT TOP (5)
[Extent1].[ID] AS [ID],
***30 more columns***
FROM ParentTable AS [Extent1]
WHERE ([Extent1].[ImageTaken] = 1) AND ([Extent1].[ImageProjected] <> 1) AND ( EXISTS (SELECT
1 AS [C1]
FROM ChildTable AS [Extent2]
WHERE [Extent1].[ID] = [Extent2].[Parent_ID]
))
Run Code Online (Sandbox Code Playgroud)
上面的查询大约需要 400 毫秒。但是,如果我从结果中排除除 ID 之外的所有列,则大约需要 100 毫秒。
如果没有结果,为什么执行时间如此不同?我查看了执行计划,它们看起来完全相同(在今天之前我从未看过执行计划,因此请谨慎对待)。
我想包括所有列,但显然我只在有结果时才需要它们。
实际执行计划
编辑 更多细节:
父表定义
USE [DB]
GO
/****** Object: Table [dbo].[Inspection_CapturedImageQueueItem] Script Date: 1/8/2018 6:23:45 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Inspection_CapturedImageQueueItem](
[ID] [INT] IDENTITY(1,1) NOT NULL,
[X] [FLOAT] NOT NULL,
[Y] [FLOAT] NOT NULL,
[Z] [FLOAT] NOT NULL,
[rX] [FLOAT] NOT NULL,
[rY] [FLOAT] NOT NULL,
[rZ] [FLOAT] NOT NULL,
[Priority] [INT] NOT NULL,
[TimeTakenUTC] [datetime] NOT NULL,
[ImageTaken] [bit] NOT NULL,
[PartProgramInstance_Id] [INT] NULL,
[PolarizerAngle1] [FLOAT] NOT NULL,
[PolarizerAngle2] [FLOAT] NOT NULL,
[ImageProjected] [bit] NOT NULL,
[LaserTransform_X] [FLOAT] NOT NULL,
[LaserTransform_Y] [FLOAT] NOT NULL,
[LaserTransform_Z] [FLOAT] NOT NULL,
[LaserTransform_rX] [FLOAT] NOT NULL,
[LaserTransform_rY] [FLOAT] NOT NULL,
[LaserTransform_rZ] [FLOAT] NOT NULL,
[LaserPosition_X] [FLOAT] NOT NULL,
[LaserPosition_Y] [FLOAT] NOT NULL,
[LaserPosition_Z] [FLOAT] NOT NULL,
[LaserPosition_rX] [FLOAT] NOT NULL,
[LaserPosition_rY] [FLOAT] NOT NULL,
[LaserPosition_rZ] [FLOAT] NOT NULL,
[ProjectionError] [INT] NOT NULL,
[LocalTransform_X] [FLOAT] NOT NULL,
[LocalTransform_Y] [FLOAT] NOT NULL,
[LocalTransform_Z] [FLOAT] NOT NULL,
[LocalTransform_rX] [FLOAT] NOT NULL,
[LocalTransform_rY] [FLOAT] NOT NULL,
[LocalTransform_rZ] [FLOAT] NOT NULL,
[IsHighAngleOfIncidence] [bit] NOT NULL,
CONSTRAINT [PK_dbo.Inspection_CapturedImageQueueItem] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [PolarizerAngle1]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [PolarizerAngle2]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [ImageProjected]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserTransform_X]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserTransform_Y]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserTransform_Z]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserTransform_rX]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserTransform_rY]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserTransform_rZ]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserPosition_X]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserPosition_Y]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserPosition_Z]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserPosition_rX]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserPosition_rY]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LaserPosition_rZ]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [ProjectionError]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LocalTransform_X]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LocalTransform_Y]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LocalTransform_Z]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LocalTransform_rX]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LocalTransform_rY]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [LocalTransform_rZ]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] ADD DEFAULT ((0)) FOR [IsHighAngleOfIncidence]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] WITH CHECK ADD CONSTRAINT [FK_dbo.Inspection_CapturedImageQueueItem_dbo.Inspection_PartProgramInstance_PartProgramInstance_Id] FOREIGN KEY([PartProgramInstance_Id])
REFERENCES [dbo].[Inspection_PartProgramInstance] ([Id])
GO
ALTER TABLE [dbo].[Inspection_CapturedImageQueueItem] CHECK CONSTRAINT [FK_dbo.Inspection_CapturedImageQueueItem_dbo.Inspection_PartProgramInstance_PartProgramInstance_Id]
GO
Run Code Online (Sandbox Code Playgroud)
子表定义
USE [DB]
GO
/****** Object: Table [dbo].[Inspection_CapturedImageItem] Script Date: 1/11/2018 9:01:34 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Inspection_CapturedImageItem](
[ID] [int] IDENTITY(1,1) NOT NULL,
[PolarizerAngle] [float] NOT NULL,
[ImageRequest_ID] [int] NULL,
[TimeTakenUTC] [datetime] NOT NULL,
[ProjectorNumber] [int] NOT NULL,
[AngleOfIncidence] [float] NOT NULL,
[MirrorRx] [float] NOT NULL,
[MirrorRy] [float] NOT NULL,
CONSTRAINT [PK_dbo.Inspection_CapturedImageItem] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] ADD DEFAULT ('1900-01-01T00:00:00.000') FOR [TimeTakenUTC]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] ADD DEFAULT ((0)) FOR [ProjectorNumber]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] ADD DEFAULT ((0)) FOR [AngleOfIncidence]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] ADD DEFAULT ((0)) FOR [MirrorRx]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] ADD DEFAULT ((0)) FOR [MirrorRy]
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] WITH CHECK ADD CONSTRAINT [FK_dbo.Inspection_CapturedImageItem_dbo.Inspection_CapturedImageQueueItem_ImageRequest_ID] FOREIGN KEY([ImageRequest_ID])
REFERENCES [dbo].[Inspection_CapturedImageQueueItem] ([ID])
GO
ALTER TABLE [dbo].[Inspection_CapturedImageItem] CHECK CONSTRAINT [FK_dbo.Inspection_CapturedImageItem_dbo.Inspection_CapturedImageQueueItem_ImageRequest_ID]
GO
Run Code Online (Sandbox Code Playgroud)
指数
该扫描所遇到的性能问题是一个神秘的问题。一般来说,我希望看到不返回任何行的扫描的 CPU 时间非常相似。没有任何计算列,并且逻辑读取计数是相同的。毫不奇怪,我无法在我的机器上重现该问题。也许它与 Express 版本有某种关系,但这是一个疯狂的猜测。
\n\n我可以为您提供解决性能问题的方法。查看实际计划,我们可以看到该Inspection_CapturedImageItem
表只有一个不同的值ImageRequest_ID
。从该表到该表的连接Inspection_CapturedImageQueueItem
是针对该表的主键和聚集键,因此使用Inspection_CapturedImageItem
外部表的嵌套循环连接计划可能会非常有效。这肯定比扫描整个Inspection_CapturedImageItem
表更有效率。
那么为什么查询优化器选择合并连接呢?聚集索引扫描成本因查询部分引入的行目标而降低。TOP (5)
事实上,通过一些数学计算,我可以为您提供过滤器的近似基数估计[Extent1].[ImageTaken] = 1) AND ([Extent1].[ImageProjected] <> 1)
:
\n\n\n优化器单位的扫描成本 = 0.0031895 + LEAST(1, ROW_GOAL /\n CARDINALITY_ESTIMATE) * (FULL_SCAN_COST \xe2\x80\x93 0.0031895)
\n\n0.0031895 + ( 5 / 基数估计) * (23.4928 + 1.11635 \xe2\x80\x93 0.0031895) = 0.0453535
\n\n基数估计 = (5 * (23.4928 + 1.11635 \xe2\x80\x93 0.0031895)) /\n (0.0453535 - 0.0031895)
\n\n基数估计 = 2918
\n
SQL Server 认为大约有 2918 行与您的过滤器匹配Inspection_CapturedImageQueueItem
。您的查询只需要前五个结果。优化器假设它不必为了这五行而扫描整个表。毕竟表里有2918个。不幸的是,您在这里过滤表中没有匹配行的谓词。对于行目标来说,这是最坏的情况。您支付扫描的全部费用,但查询优化器会创建一个计划,假设您只需要扫描表的 0.3%。
有两种方法可以解决这个问题:您可以为优化器提供更好的信息,或者可以强制优化器使用您认为更好的计划。如果可能的话,通常首选第一个选项。这里没有足够的详细信息来深入研究,但您可能会从ImageTaken
和ImageProjected
列的统计信息更新中受益。更新theImageRequest_ID
列的统计数据Inspection_CapturedImageItem
也可能是有益的。查询优化器估计有 42 个不同的行,但实际上只有 1 个。
如果您确信自己理解为什么会得到一个糟糕的计划,并且数据不会随着时间的推移而改变,您可以考虑查询提示。禁用行目标的使用提示HINT(\'DISABLE_OPTIMIZER_ROWGOAL\')
可能是一个不错的选择。通过该提示,您将指示查询优化器不要优化查询以尽快返回前五行。相反,将创建一个计划来有效地返回结果集中的所有行。即使基数估计很差,Inspection_CapturedImageItem
您也可能最终得到一个嵌套循环连接,该连接应该比执行扫描的查询更快。
归档时间: |
|
查看次数: |
179 次 |
最近记录: |