Ash*_*raf 4 performance sql-server optimization execution-plan sql-server-2016 query-performance
我正在研究一个场景,在这个场景中,我提供了一个变量值。当我传递 Null 值时,查询引擎没有扫描连接表。根据逻辑查询处理,首先执行FROM子句,然后执行ON和JOIN。但在这种情况下,查询引擎直接转到Where子句。当变量的值为 NULL 时,任何人都可以解释行为查询引擎。我正在使用 SQL Server 2016。
当值改变时
你看到了一个矛盾检测的例子。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值。