Execution Plan is different when Constant Variable is Null
I am working on a scenario in which I am providing a variable a value. When I pass Null value, the Query Engine didn't scan the Join tables. As per Logical Query Processing, first FROM Clause Executes, then ON and JOIN executes. But in this Case the Query Engine direct go to Where Clause. Could anyone please explain the Behavior Query Engine when there is a NULL value of a Variable. I am using SQL Server 2016.
When the Value is changed then
sql-server query-performance sql-server-2016 optimization execution-plan
New contributor
add a comment |
I am working on a scenario in which I am providing a variable a value. When I pass Null value, the Query Engine didn't scan the Join tables. As per Logical Query Processing, first FROM Clause Executes, then ON and JOIN executes. But in this Case the Query Engine direct go to Where Clause. Could anyone please explain the Behavior Query Engine when there is a NULL value of a Variable. I am using SQL Server 2016.
When the Value is changed then
sql-server query-performance sql-server-2016 optimization execution-plan
New contributor
add a comment |
I am working on a scenario in which I am providing a variable a value. When I pass Null value, the Query Engine didn't scan the Join tables. As per Logical Query Processing, first FROM Clause Executes, then ON and JOIN executes. But in this Case the Query Engine direct go to Where Clause. Could anyone please explain the Behavior Query Engine when there is a NULL value of a Variable. I am using SQL Server 2016.
When the Value is changed then
sql-server query-performance sql-server-2016 optimization execution-plan
New contributor
I am working on a scenario in which I am providing a variable a value. When I pass Null value, the Query Engine didn't scan the Join tables. As per Logical Query Processing, first FROM Clause Executes, then ON and JOIN executes. But in this Case the Query Engine direct go to Where Clause. Could anyone please explain the Behavior Query Engine when there is a NULL value of a Variable. I am using SQL Server 2016.
When the Value is changed then
sql-server query-performance sql-server-2016 optimization execution-plan
sql-server query-performance sql-server-2016 optimization execution-plan
New contributor
New contributor
New contributor
asked 6 hours ago
AshrafAshraf
162
162
New contributor
New contributor
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You're seeing an example of contradiction detection. SQL Server's query optimizer is smart enough to perform a few quick checks at the outset of query processing to determine if it can take any shortcuts to return results without doing much (any?!) work. One such short circuit is to check if the where clause contains an "impossible" limit, such as:
WHERE 1=0
or
WHERE NULL = NULL
SQL Server sees you are comparing something to NULL
, which always returns false, and simply returns an empty resultset. If the items in your WHERE
clause were separated with OR
instead of AND
, then further checks would be performed and you might not see the constant-scan plan.
Comparing any value to NULL
using =
always returns false. You may want to use WHERE @c IS NULL
instead. If you rewrite your query using that syntax, you'll see SQL Server does in fact "run" the query. Consider this:
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;
The query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c = NULL;
Versus the query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c IS NULL;
The problems around comparing NULL
values applies to JOIN
conditions as well. Consider this:
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
);
I'll insert a row into each table with the value of i
set to NULL
:
INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);
Now, if we try to JOIN
the two tables in a "simple" query, we get no results returned, since NULL
cannot be compared to anything, not even another NULL
value!
SELECT *
FROM #t t
INNER JOIN #s s ON t.i = s.i;
Both tables are scanned by the query processor, as shown in the query plan:
In other words, be careful using NULL
values.
In future, please don't post pictures of code, instead create a minimal, complete, and verifiable example that others can use in their answer.
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "182"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Ashraf is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f227188%2fexecution-plan-is-different-when-constant-variable-is-null%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You're seeing an example of contradiction detection. SQL Server's query optimizer is smart enough to perform a few quick checks at the outset of query processing to determine if it can take any shortcuts to return results without doing much (any?!) work. One such short circuit is to check if the where clause contains an "impossible" limit, such as:
WHERE 1=0
or
WHERE NULL = NULL
SQL Server sees you are comparing something to NULL
, which always returns false, and simply returns an empty resultset. If the items in your WHERE
clause were separated with OR
instead of AND
, then further checks would be performed and you might not see the constant-scan plan.
Comparing any value to NULL
using =
always returns false. You may want to use WHERE @c IS NULL
instead. If you rewrite your query using that syntax, you'll see SQL Server does in fact "run" the query. Consider this:
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;
The query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c = NULL;
Versus the query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c IS NULL;
The problems around comparing NULL
values applies to JOIN
conditions as well. Consider this:
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
);
I'll insert a row into each table with the value of i
set to NULL
:
INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);
Now, if we try to JOIN
the two tables in a "simple" query, we get no results returned, since NULL
cannot be compared to anything, not even another NULL
value!
SELECT *
FROM #t t
INNER JOIN #s s ON t.i = s.i;
Both tables are scanned by the query processor, as shown in the query plan:
In other words, be careful using NULL
values.
In future, please don't post pictures of code, instead create a minimal, complete, and verifiable example that others can use in their answer.
add a comment |
You're seeing an example of contradiction detection. SQL Server's query optimizer is smart enough to perform a few quick checks at the outset of query processing to determine if it can take any shortcuts to return results without doing much (any?!) work. One such short circuit is to check if the where clause contains an "impossible" limit, such as:
WHERE 1=0
or
WHERE NULL = NULL
SQL Server sees you are comparing something to NULL
, which always returns false, and simply returns an empty resultset. If the items in your WHERE
clause were separated with OR
instead of AND
, then further checks would be performed and you might not see the constant-scan plan.
Comparing any value to NULL
using =
always returns false. You may want to use WHERE @c IS NULL
instead. If you rewrite your query using that syntax, you'll see SQL Server does in fact "run" the query. Consider this:
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;
The query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c = NULL;
Versus the query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c IS NULL;
The problems around comparing NULL
values applies to JOIN
conditions as well. Consider this:
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
);
I'll insert a row into each table with the value of i
set to NULL
:
INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);
Now, if we try to JOIN
the two tables in a "simple" query, we get no results returned, since NULL
cannot be compared to anything, not even another NULL
value!
SELECT *
FROM #t t
INNER JOIN #s s ON t.i = s.i;
Both tables are scanned by the query processor, as shown in the query plan:
In other words, be careful using NULL
values.
In future, please don't post pictures of code, instead create a minimal, complete, and verifiable example that others can use in their answer.
add a comment |
You're seeing an example of contradiction detection. SQL Server's query optimizer is smart enough to perform a few quick checks at the outset of query processing to determine if it can take any shortcuts to return results without doing much (any?!) work. One such short circuit is to check if the where clause contains an "impossible" limit, such as:
WHERE 1=0
or
WHERE NULL = NULL
SQL Server sees you are comparing something to NULL
, which always returns false, and simply returns an empty resultset. If the items in your WHERE
clause were separated with OR
instead of AND
, then further checks would be performed and you might not see the constant-scan plan.
Comparing any value to NULL
using =
always returns false. You may want to use WHERE @c IS NULL
instead. If you rewrite your query using that syntax, you'll see SQL Server does in fact "run" the query. Consider this:
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;
The query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c = NULL;
Versus the query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c IS NULL;
The problems around comparing NULL
values applies to JOIN
conditions as well. Consider this:
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
);
I'll insert a row into each table with the value of i
set to NULL
:
INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);
Now, if we try to JOIN
the two tables in a "simple" query, we get no results returned, since NULL
cannot be compared to anything, not even another NULL
value!
SELECT *
FROM #t t
INNER JOIN #s s ON t.i = s.i;
Both tables are scanned by the query processor, as shown in the query plan:
In other words, be careful using NULL
values.
In future, please don't post pictures of code, instead create a minimal, complete, and verifiable example that others can use in their answer.
You're seeing an example of contradiction detection. SQL Server's query optimizer is smart enough to perform a few quick checks at the outset of query processing to determine if it can take any shortcuts to return results without doing much (any?!) work. One such short circuit is to check if the where clause contains an "impossible" limit, such as:
WHERE 1=0
or
WHERE NULL = NULL
SQL Server sees you are comparing something to NULL
, which always returns false, and simply returns an empty resultset. If the items in your WHERE
clause were separated with OR
instead of AND
, then further checks would be performed and you might not see the constant-scan plan.
Comparing any value to NULL
using =
always returns false. You may want to use WHERE @c IS NULL
instead. If you rewrite your query using that syntax, you'll see SQL Server does in fact "run" the query. Consider this:
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;
The query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c = NULL;
Versus the query plan for this query:
SELECT *
FROM #t t
WHERE t.i = 1
AND @c IS NULL;
The problems around comparing NULL
values applies to JOIN
conditions as well. Consider this:
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
);
I'll insert a row into each table with the value of i
set to NULL
:
INSERT INTO #t (i) VALUES (NULL);
INSERT INTO #s (i) VALUES (NULL);
Now, if we try to JOIN
the two tables in a "simple" query, we get no results returned, since NULL
cannot be compared to anything, not even another NULL
value!
SELECT *
FROM #t t
INNER JOIN #s s ON t.i = s.i;
Both tables are scanned by the query processor, as shown in the query plan:
In other words, be careful using NULL
values.
In future, please don't post pictures of code, instead create a minimal, complete, and verifiable example that others can use in their answer.
edited 1 hour ago
answered 2 hours ago
Max VernonMax Vernon
50.1k13111220
50.1k13111220
add a comment |
add a comment |
Ashraf is a new contributor. Be nice, and check out our Code of Conduct.
Ashraf is a new contributor. Be nice, and check out our Code of Conduct.
Ashraf is a new contributor. Be nice, and check out our Code of Conduct.
Ashraf is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Database Administrators Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f227188%2fexecution-plan-is-different-when-constant-variable-is-null%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown