Sql server 为什么加入要花这么长时间?
我在数据库服务器上运行以下查询,但运行大约需要30秒,我无法找出原因Sql server 为什么加入要花这么长时间?,sql-server,sql-server-2008,join,indexing,sql-execution-plan,Sql Server,Sql Server 2008,Join,Indexing,Sql Execution Plan,我在数据库服务器上运行以下查询,但运行大约需要30秒,我无法找出原因 SELECT * FROM [dbo].[PackageInstance] AS packInst INNER JOIN [dbo].[PackageDefinition] AS packageDef ON packInst.[PackageDefinitionID] = packageDef.[PackageDefinitionID] LEFT OUTER JOIN [dbo].[PackageInstan
SELECT *
FROM [dbo].[PackageInstance] AS packInst
INNER JOIN [dbo].[PackageDefinition] AS packageDef
ON packInst.[PackageDefinitionID] = packageDef.[PackageDefinitionID]
LEFT OUTER JOIN [dbo].[PackageInstanceContextDef] AS contextDef
ON packInst.[PackageInstanceID] = contextDef.[PackageInstanceID]
这就产生了下面的执行计划,在我看来这是一个不错的计划……所以我不明白为什么执行所产生的数据只有100000条记录(对于SQL Server来说,这应该是一个闲逛)
你知道是什么导致了这么长的执行时间吗
我查看了Profiler中的查询,以了解其中的统计信息,如下所示:
CPU - 4711
Reads - 744453
Writes - 9
Duration - 26329
以下是表格定义:
CREATE TABLE [dbo].[PackageDefinition](
[PackageDefinitionID] [int] IDENTITY(1,1) NOT NULL,
[ts] [timestamp] NOT NULL,
[ProgramID] [int] NULL,
[VendorID] [int] NULL,
[PackageExecutionTypeID] [int] NULL,
[PackageDefinitionStatusID] [int] NOT NULL,
[IsInternal] [bit] NOT NULL,
[Name] [dbo].[D_Name] NOT NULL,
[Description] [dbo].[D_Description] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[PublishedDate] [datetime] NULL,
[OwnerUserGuid] [uniqueidentifier] NOT NULL,
[ProcessDefinitionMainID] [int] NULL,
[KeyInfoHtml] [nvarchar](max) NULL,
[DescriptionHtml] [nvarchar](max) NULL,
[WhatToExpectHtml] [nvarchar](max) NULL,
[BestPracticesHtml] [nvarchar](max) NULL,
[RecommendedJourneysHtml] [nvarchar](max) NULL,
[RequiresSLAAgreement] [bit] NOT NULL,
[SLAFileAssetID] [int] NULL,
[ImageDataID] [int] NULL,
[VideoHtml] [nvarchar](max) NULL,
[VideoAssetID] [int] NULL,
[UseMapCosts] [bit] NOT NULL,
[CostMin] [money] NOT NULL,
[CostMax] [money] NOT NULL,
[LandingPageVisitCount] [int] NOT NULL,
[IsDeleted] [dbo].[D_IsDeleted] NOT NULL,
[CreatedByUserGuid] [uniqueidentifier] NOT NULL,
[OrderHtml] [nvarchar](max) NULL,
CONSTRAINT [PK_PackageDefinition] PRIMARY KEY CLUSTERED
(
[PackageDefinitionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[PackageInstance](
[PackageInstanceID] [int] IDENTITY(1,1) NOT NULL,
[ts] [timestamp] NOT NULL,
[PackageDefinitionID] [int] NOT NULL,
[PackageStatusID] [int] NOT NULL,
[Name] [dbo].[D_Description] NOT NULL,
[CampaignID] [int] NULL,
[MarketingPlanID] [int] NULL,
[CountryID] [int] NULL,
[DateEntered] [datetime] NULL,
[DateExecuted] [datetime] NULL,
[ProcessID] [int] NULL,
[OrderedByUserGuid] [uniqueidentifier] NULL,
[RequestedByUserGuid] [uniqueidentifier] NULL,
[SLAEndDate] [datetime] NULL,
CONSTRAINT [PK_PackageInstance] PRIMARY KEY CLUSTERED
(
[PackageInstanceID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[PackageInstanceContextDef](
[PackageInstanceContextDefID] [int] IDENTITY(1,1) NOT NULL,
[ts] [timestamp] NOT NULL,
[PackageInstanceID] [int] NOT NULL,
[ContextObjectDefID] [int] NOT NULL,
[EnteredFieldValue] [varchar](max) NULL,
[SelectedListValueID] [int] NULL,
[AssetIdsString] [nvarchar](max) NULL,
[SelectedListValueIdsString] [nvarchar](max) NULL,
[ContextObjectFieldName] [nvarchar](30) NOT NULL,
CONSTRAINT [PK_PackageInstanceContextDef] PRIMARY KEY CLUSTERED
(
[PackageInstanceContextDefID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
在
选择*
它将始终扫描,因为您需要所有列。有聚集索引吗?如果添加以下索引会发生什么情况
CREATE NONCLUSTERED INDEX ix ON PackageDefinition(PackageDefinitionID)
…并尝试以下操作以减少进入排序的数据的宽度
SELECT packInst.*,
packageDef2.*,
contextDef.*
FROM [dbo].[PackageInstance] AS packInst
INNER MERGE JOIN [dbo].[PackageDefinition] AS packageDef
ON packInst.[PackageDefinitionID] = packageDef.[PackageDefinitionID]
LEFT OUTER MERGE JOIN [dbo].[PackageInstanceContextDef] AS contextDef
ON packInst.[PackageInstanceID] = contextDef.[PackageInstanceID]
INNER MERGE JOIN [dbo].[PackageDefinition] AS packageDef2
ON packageDef.[PackageDefinitionID] = packageDef2.[PackageDefinitionID]
当然,不应该使用
*
,因为即使您需要所有列,您肯定不需要两次使用相同的列作为连接的结果,但这只是为了保持原始查询的语义。结果是@MartinSmith建议的答案。因为PackageDefinition表包含大约8个NVARCHAR(MAX)列,当创建结果连接时,超过100k行,这导致varchar(MAX)值被反复读取,并且它们存在于行外页面中。因此需要大量的逻辑读取
感谢大家的支持,我只需要想办法让实体框架生成我想要的查询。其他进程是否存在CPU/磁盘争用?PackageInstanceContextDef上索引扫描的执行计数是多少?(在工具提示中)探查器中有排序警告吗?如果您尝试在readuncommitted
隔离级别执行操作,会怎么样?可能会遇到阻塞@安多马尔-将是1。合并联接只处理每个输入一次。744453读取大于5GB的数据。这些排有多宽?您可能也有严重的碎片问题?@Penfold-所有那些max
列都在破坏性能。不幸的是,我要做的是找出为什么我的Linq to Entities查询耗时如此之长,以至于我无法控制可以选择哪些字段,所以我需要所有字段!!:(在生产版本中,我会删除星号并按名称添加列。每个表的主键上都有聚集索引。@Penfold:您要求我们帮助进行测试查询,然后选择了*。?是的,如果您愿意,我可以列出每一列,但其中有一些列,我认为这没有帮助。)p看来我不需要所有的列。根据定义,您不需要所有列,因为在多个列中有相同数据的联接。SELECT*是SQL反模式,不应该在生产代码中使用。如果您的ORM不能处理这一问题,它是一个糟糕的工具,不应该使用。@HLGEM我完全同意您在生产c中使用SELECT*ode和ORM应该能够限制返回的数据。然而,我在这里说的不是我想要用户选择*或者实体框架不能解决它需要什么,而是我使用SELECT*使语句更易于查看,因为框架将返回大约50列。是吗您是否尝试了我的答案?我很想知道,在排序操作之后检索大型列,即使是以访问PackageDefinition
两次为代价,是否也能改善情况?