Sql server 为什么加入要花这么长时间?

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

我在数据库服务器上运行以下查询,但运行大约需要30秒,我无法找出原因

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
两次为代价,是否也能改善情况?