为什么我的执行计划(有时)包括左连接?

Joh*_*ohn 4 join sql-server execution-plan sql-server-2014

我发现了一个类似的问题,我知道为了查询表格

SELECT COUNT(1)
FROM foo f
LEFT OUTER JOIN bar b ON f.Value = b.Value AND f.Value = b.Value2
Run Code Online (Sandbox Code Playgroud)

要在不接触的情况下执行bar,需要在有问题的两列上有一个唯一索引。

事实上,到目前为止,这有效,表被定义为:

CREATE TABLE [dbo].[Foo](
    [Value] [varchar](255) NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[Bar](
    [Value] [varchar](1024) NULL,
    [Value2] [varchar](1024) NULL
)

CREATE UNIQUE CLUSTERED INDEX [IX] ON [dbo].[Bar]
(
    [Value] ASC,
    [Value2] ASC
)
Run Code Online (Sandbox Code Playgroud)

查询计划没有触及bar,太好了。

在我探索为什么这在我编写的某些应用程序的实际查询中不起作用时,我将那里的查询简化为以下简单的测试,并且查询计划器无法将其从桌子上移开bar

WITH numbers AS (
    SELECT 1 AS i
    UNION ALL SELECT i + 1
    FROM numbers
    WHERE i < 10
)
SELECT COUNT(1)
FROM numbers n
LEFT OUTER JOIN bar b ON n.i = b.Value AND n.i = b.Value2
;
Run Code Online (Sandbox Code Playgroud)

这确实触及吧。嗯。

有任何想法吗?为什么查询规划器认为这与其他查询有任何不同?

(我的实际问题不使用这个递归表表达式,它实际上就像演示案例,两列上的简单连接 - 我无法理解为什么它不会在计数场景中单独留下连接表。)

Aar*_*and 11

我怀疑区别在于隐式转换,这可能会妨碍。例如,Bar如果它具有兼容的数据类型,则不会被触及:

CREATE TABLE [dbo].[Bar]
(
    [Value] int NULL,
    [Value2] int NULL
);
Run Code Online (Sandbox Code Playgroud)