为什么这两个查询的执行计划如此不同?

时间:2015-07-16 19:38:24

标签: sql-server

我有一个包含以下现有表格的数据库:

CREATE TABLE [dbo].[sites]
(
    [site_id] [uniqueidentifier] NOT NULL,
    [description] [nvarchar](80) NOT NULL,
    [parent_id] [uniqueidentifier] NULL,
    [domain_id] [int] NOT NULL,

    CONSTRAINT [PK_sites] PRIMARY KEY NONCLUSTERED ( site_id] ASC
)

ALTER TABLE [dbo].[sites] WITH CHECK 
  ADD CONSTRAINT [FK_sites_sites] 
  FOREIGN KEY([parent_id]) REFERENCES [dbo].[sites] ([site_id])

ALTER TABLE [dbo].[sites] CHECK CONSTRAINT [FK_sites_sites]

我添加了另一个看起来像这样的表:

CREATE TABLE [dbo].[site_map]
(
    [force_id] [int] NOT NULL,
    [source_id] [int] NOT NULL,
    [camera_id] [int] NOT NULL,
    [site_id] [uniqueidentifier] NOT NULL,

    CONSTRAINT [PK_site_map] PRIMARY KEY CLUSTERED 
        ([force_id] ASC, [source_id] ASC, [camera_id] ASC)
)

ALTER TABLE [dbo].[site_map] WITH CHECK 
  ADD CONSTRAINT [FK_site_map_sites] 
  FOREIGN KEY([site_id]) REFERENCES [dbo].[sites] ([site_id])

ALTER TABLE [dbo].[site_map] CHECK CONSTRAINT [FK_site_map_sites]

现在,当我执行此查询时:

SELECT 
    m.[site_id], c.[description], s.[site_id] AS ReaderId, s.[domain_id]
FROM 
    [dbo].[site_map] AS m
LEFT OUTER JOIN 
    [dbo].[sites] AS c ON m.[site_id] = c.[site_id]
LEFT OUTER JOIN 
    [dbo].[sites] AS s ON c.[parent_id] = s.[site_id]
WHERE 
    [force_id] = @forceId 
    AND [source_id] = @sourceid 
    AND [camera_id] = @cameraId

我得到一个执行两个嵌套循环的查询计划。但是,当我更改查询时,它的内容如下:

SELECT 
    m.[site_id], c.[description], s.[site_id] AS ReaderId, s.[domain_d]
FROM 
    [dbo].[site_map] AS m
INNER JOIN 
    [dbo].[sites] AS c ON m.[site_id] = c.[site_id]
INNER JOIN 
    [dbo].[sites] AS s ON c.[parent_id] = s.[site_id]
WHERE 
    [force_id] = @forceId 
    AND [source_id] = @sourceid 
    AND [camera_id] = @cameraId

查询计划执行四个嵌套循环!唯一改变的是连接类型。为什么查询计划如此不同?

2 个答案:

答案 0 :(得分:0)

您是否真的注意到性能差异?

我的猜测是INNER JOIN仍然更有效率。看看"执行次数"查询计划中每个嵌套循环操作的数量。我猜测LEFT JOINS有天真的嵌套循环操作,或者至少是一个效率较低的扫描输入,并且INNER JOIN的执行次数较少,可能不是左边的完整笛卡尔循环在x侧右侧,它们可能只在左侧每行执行一次。很难说没有看到查询计划。

我将SET STATISTICS IO打开,刷新您的缓存,看看每次操作得到多少逻辑读取,看看有什么区别。

答案 1 :(得分:0)

(在SQL Server Compact DB上,可能表现不同):

SELECT m.[site_id], c.[description], s.[site_id] AS ReaderId, s.[domain_id]
FROM [site_map] AS m
LEFT OUTER JOIN [sites] AS c ON m.[site_id] = c.[site_id]
LEFT OUTER JOIN [sites] AS s ON c.[parent_id] = s.[site_id]
WHERE [force_id] = 1 AND [source_id] = 1 AND [camera_id] = 1

Left Outer Join Estimated Execution Plan

SELECT m.[site_id], c.[description], s.[site_id] AS ReaderId, s.[domain_id]
FROM [site_map] AS m
INNER JOIN [sites] AS c ON m.[site_id] = c.[site_id]
INNER JOIN [sites] AS s ON c.[parent_id] = s.[site_id]
WHERE [force_id] = 1 AND [source_id] = 1 AND [camera_id] = 1

Inner Join Estimated Execution Plan

抱歉,我在第二个执行计划中看不到四个循环。如果您提供执行计划的屏幕截图,那将会很有帮助。