【问题标题】:Does SQL Server 2012 Lazy JoinSQL Server 2012 是否延迟加入
【发布时间】:2013-12-06 22:17:10
【问题描述】:

我正在开发一个允许用户动态选择他们看到的内容的应用程序。属于的列和表的列表是巨大的。我正在构建一个动态查询,但我不想存储所有的连接逻辑,如果我没有的话。 一个例子是我有一个对 1​​0 个表有 LEFT JOINS 的查询,但我只选择和过滤一个表。 SQL Server 2012 是否足够智能,不会加入其他不需要的表?

我知道 Oracle 的 DBMS 是这样工作的,但我的公司使用的是 SQL Server 2012,所以我坚持这样做。

最后 4 个 LEFT JOINS 不需要执行的示例查询:

SELECT [IncidentIncidentNumberModValue].[IncidentNumber]
    ,IncidentNumberModifierNotValue.[Value] AS IncidentNumberNotValue
    ,[Incident].[IncidentDate]
    ,[Incident].[ResponseNumber]
    ,[Incident].[PatientCareReportNumber]
    ,[IncidentType].[Value] AS IncidentType
    ,[SceneStreetAddressModValue].[StreetAddress2] AS IncidentAddress
    ,IncidentStreetAddressNotValue.[Value] AS IncidentAddressNotValue
    ,COUNT(*) OVER() AS TotalRecordCount
FROM [EmsEvent].[Incident]
    LEFT JOIN [Resource].[IncidentType] ON [EmsEvent].[Incident].[IncidentType] = [Resource].[IncidentType].[IncidentTypeID]
    LEFT JOIN [EmsEvent].[IncidentIncidentNumberModValue] ON [EmsEvent].[Incident].[IncidentID] = [EmsEvent].[IncidentIncidentNumberModValue].[IncidentID]
    LEFT JOIN [GlobalResource].[IncidentNumberModifier] ON [EmsEvent].[IncidentIncidentNumberModValue].[NotValue] = [GlobalResource].[IncidentNumberModifier].[DataElementID]
    LEFT JOIN [GlobalResource].[NotValue] IncidentNumberModifierNotValue ON [GlobalResource].[IncidentNumberModifier].[NotValueID] = IncidentNumberModifierNotValue.[NotValueID]
    LEFT JOIN [EmsEvent].[Scene] ON [EmsEvent].[Scene].[IncidentID] = [EmsEvent].[Incident].[IncidentID]
    LEFT JOIN [EmsEvent].[SceneStreetAddressModValue] ON [EmsEvent].[Scene].[SceneID] = [EmsEvent].[SceneStreetAddressModValue].[SceneID]
    LEFT JOIN [GlobalResource].[IncidentStreetAddressModifier] ON [EmsEvent].[SceneStreetAddressModValue].[NotValue] = [GlobalResource].[IncidentStreetAddressModifier].[DataElementID]
    LEFT JOIN [GlobalResource].[NotValue] IncidentStreetAddressNotValue ON [GlobalResource].[IncidentStreetAddressModifier].[NotValueID] = IncidentStreetAddressNotValue.[NotValueID]
    LEFT JOIN [EmsEvent].[CustomConfig] on [EmsEvent].[Incident].[IncidentID] = [EmsEvent].[CustomConfig].[IncidentID]
    LEFT JOIN [EmsEvent].[IncidentDisasterType] on [EmsEvent].[Incident].[IncidentID] = [EmsEvent].[IncidentDisasterType].[IncidentID]
    LEFT JOIN [EmsEvent].[Response] on [EmsEvent].[Scene].[SceneID] = [EmsEvent].[Response].[SceneID]
    LEFT JOIN [EmsEvent].[CrewMember] on [EmsEvent].[Response].[ResponseID] = [EmsEvent].[CrewMember].[ResponseInformationID]

WHERE [EmsEvent].[Incident].[DeletedStatus] = 0
    AND [EmsEvent].[Incident].AgencyID = '607CEE05-276D-49A1-B6BF-FD606EFC2377'
ORDER BY [EmsEvent].[IncidentIncidentNumberModValue].[IncidentNumber] ASC
OFFSET 0 ROWS
FETCH NEXT 25 ROWS ONLY
OPTION(recompile)

【问题讨论】:

  • 使用OPTION (RECOMPILE) 将告诉优化器在每次执行查询时创建新的查询计划。如果您有不需要的 JOINs,它们将被排除在外。确保“未使用”连接表上没有过滤器。
  • 嗯,当我将其添加到查询的末尾时,执行计划仍然显示加入了不需要的表。有什么技巧可以让它按照我需要的方式工作吗?
  • 我用有问题的查询更新了原始帖子。

标签: sql sql-server-2012 left-join database


【解决方案1】:

这取决于您在连接中使用的左外连接表中的哪一列。

如果该列是主键或具有唯一约束,如果该表在查询的其他地方没有被引用,则该表将被排除在查询计划之外。

您的最后四个表似乎没有根据各自的主键连接。

这样的表格:

create table Parent
(
  ParentID int primary key
)

create table Child
(
  ChildID int primary key,
  ParentID int references Parent(ParentID)
)

此查询不会使用表Parent

select C.*
from Child as C
  left outer join Parent as P
    on P.ParentID = C.ParentID

但是这个查询必须使用左外连接子表,因为如果外键命中不止一次,它可能会在结果中添加行。

select P.*
from Parent as P
  left outer join Child as C
    on P.ParentID = C.ParentID

【讨论】:

  • 我看到是因为我加入了这些表上的外键 SQL 无论如何都会尝试加入它们。添加 DISTINCT 会改变这种情况吗?
  • @Ranger1230 是的,至少在我的回答中的简单情况下。然后 SQL Server 就会知道 join 不能负责向结果集中添加更多行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 2013-06-17
  • 1970-01-01
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多