当常量变量为 Null 时,执行计划不同

Ash*_*raf 4 performance sql-server optimization execution-plan sql-server-2016 query-performance

我正在研究一个场景,在这个场景中,我提供了一个变量值。当我传递 Null 值时,查询引擎没有扫描连接表。根据逻辑查询处理,首先执行FROM子句,然后执行ONJOIN。但在这种情况下,查询引擎直接转到Where子句。当变量的值为 NULL 时,任何人都可以解释行为查询引擎。我正在使用 SQL Server 2016。

在此处输入图片说明

当值改变时

在此处输入图片说明

Han*_*non 8

你看到了一个矛盾检测的例子。SQL Server 的查询优化器足够聪明,可以在查询处理开始时执行一些快速检查,以确定是否可以采取任何快捷方式返回结果,而无需做太多(任何?!)工作。一种这样的短路是检查 where 子句是否包含“不可能”的限制,例如:

WHERE 1=0
Run Code Online (Sandbox Code Playgroud)

或者

WHERE NULL = NULL
Run Code Online (Sandbox Code Playgroud)

SQL Server 看到您正在将某些内容与 进行比较NULL,它总是返回 false,并且只返回一个空的结果集。如果您的WHERE子句中的项目用OR代替分隔AND,则将执行进一步检查,您可能看不到常量扫描计划。

将任何值与NULLusing进行比较= 总是返回 false。您可能想WHERE @c IS NULL改用。如果您使用该语法重写查询,您将看到 SQL Server 实际上“运行”了查询。考虑一下:

IF OBJECT_ID(N'tempdb..#t', N'U') IS NOT NULL DROP TABLE #t;
CREATE TABLE #t 
(
    i int NOT NULL
);

DECLARE @c int = 1;
Run Code Online (Sandbox Code Playgroud)

此查询的查询计划:

SELECT *
FROM #t t
WHERE t.i = 1
    AND @c = NULL;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

与此查询的查询计划对比:

SELECT *
FROM #t t
WHERE t.i = 1
    AND @c IS NULL;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

比较NULL值的问题也适用于JOIN条件。考虑一下:

IF OBJECT_ID(N'tempdb..#t', N'U') IS NOT NULL DROP TABLE #t;
CREATE TABLE #t 
(
    i int NULL
);

IF OBJECT_ID(N'tempdb..#s', N'U') IS NOT NULL DROP TABLE #s;
CREATE TABLE #s 
(
    i int NULL
);

Run Code Online (Sandbox Code Playgroud)

我将在每个表中插入一行,其值i设置为NULL

INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);
Run Code Online (Sandbox Code Playgroud)

现在,如果我们JOIN在“简单”查询中尝试对两个表进行比较,我们将不会返回任何结果,因为NULL无法与任何内容进行比较,甚至无法与其他NULL值进行比较!

SELECT *
FROM #t t
    INNER JOIN #s s ON t.i = s.i;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

两个表都由查询处理器扫描,如查询计划所示:

在此处输入图片说明

换句话说,小心使用NULL值。