Why doesn't SQL Optimizer use my constraint? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 00:00UTC (8:00pm US/Eastern)Single year column and multiple weeks columns into single year/week column with PIVOTValidate a column to accept only certain age limit from birthdate given using check constraintNull Values in a CASE statementSelect Into removes IDENTITY property from target tableSQL 2005 Unused proceduresInvestigating errors from strange queryStatistics update with automatic sampling messes up density vector and histogramWhy we need to optimize CONTAINED IN clause of FOR_SYSTEM TIME using check constraint?Understanding why a query is slowGenerate SQL Table DDL from a View
What is the font for "b" letter?
Why is my ESD wriststrap failing with nitrile gloves on?
What's the meaning of "fortified infraction restraint"?
What was the first language to use conditional keywords?
How does the math work when buying airline miles?
Do wooden building fires get hotter than 600°C?
How come Sam didn't become Lord of Horn Hill?
How do I find out the mythology and history of my Fortress?
Why should I vote and accept answers?
Generate an RGB colour grid
Did Krishna say in Bhagavad Gita "I am in every living being"
What would you call this weird metallic apparatus that allows you to lift people?
How to write the following sign?
What does it mean that physics no longer uses mechanical models to describe phenomena?
The code below, is it ill-formed NDR or is it well formed?
If windows 7 doesn't support WSL, then what does Linux subsystem option mean?
How do I make this wiring inside cabinet safer?
Localisation of Category
Export Xpubkey from Bitcoin Core
Drawing without replacement: why the order of draw is irrelevant?
What initially awakened the Balrog?
How fail-safe is nr as stop bytes?
Why aren't air breathing engines used as small first stages?
Effects on objects due to a brief relocation of massive amounts of mass
Why doesn't SQL Optimizer use my constraint?
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 23, 2019 at 00:00UTC (8:00pm US/Eastern)Single year column and multiple weeks columns into single year/week column with PIVOTValidate a column to accept only certain age limit from birthdate given using check constraintNull Values in a CASE statementSelect Into removes IDENTITY property from target tableSQL 2005 Unused proceduresInvestigating errors from strange queryStatistics update with automatic sampling messes up density vector and histogramWhy we need to optimize CONTAINED IN clause of FOR_SYSTEM TIME using check constraint?Understanding why a query is slowGenerate SQL Table DDL from a View
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I want to create a table with a NOT NULL bool column.
I use TINYINT with CHECK constraint BETWEEN 0 and 1. The constraint is new and thus trusted
Now I would expect that SQL optimizer now knows that this column can only be 0 and 1 so when I write query col >= 2 I will see Constant Scan in actual execution plan (like when I would when check for NULL or SELECT TOP (0)
But this is not the case, it opts for the table Scan. Do I also need to have index on this column?
In my test below I use TINYINT with CHECK constraint. User Defined Type based on TINYINT with bound RULE and good old BIT.
GO
CREATE TYPE dbo.myBool
FROM [INT] NOT NULL
GO
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
go
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
GO
DROP TABLE IF EXISTS dbo.RuleTest
CREATE TABLE dbo.RuleTest
(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
, oldSchoolBool TINYINT NOT NULL CHECK (oldSchoolBool BETWEEN 0 AND 1)
, customBool dbo.myBool NOT NULL
, myBit BIT NOT NULL
)
;WITH tally (n)
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS a(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS b(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS c(n)
)
INSERT INTO dbo.RuleTest
(oldSchoolBool, customBool, myBit)
SELECT
ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
FROM tally t
SET STATISTICS IO ON;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool IS NULL
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.customBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.myBit >= 2
SET STATISTICS IO OFF;
I see one Constant Scan for the NULL check and 3 table scans for the rest.
t-sql sql-server-2016
add a comment |
I want to create a table with a NOT NULL bool column.
I use TINYINT with CHECK constraint BETWEEN 0 and 1. The constraint is new and thus trusted
Now I would expect that SQL optimizer now knows that this column can only be 0 and 1 so when I write query col >= 2 I will see Constant Scan in actual execution plan (like when I would when check for NULL or SELECT TOP (0)
But this is not the case, it opts for the table Scan. Do I also need to have index on this column?
In my test below I use TINYINT with CHECK constraint. User Defined Type based on TINYINT with bound RULE and good old BIT.
GO
CREATE TYPE dbo.myBool
FROM [INT] NOT NULL
GO
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
go
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
GO
DROP TABLE IF EXISTS dbo.RuleTest
CREATE TABLE dbo.RuleTest
(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
, oldSchoolBool TINYINT NOT NULL CHECK (oldSchoolBool BETWEEN 0 AND 1)
, customBool dbo.myBool NOT NULL
, myBit BIT NOT NULL
)
;WITH tally (n)
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS a(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS b(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS c(n)
)
INSERT INTO dbo.RuleTest
(oldSchoolBool, customBool, myBit)
SELECT
ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
FROM tally t
SET STATISTICS IO ON;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool IS NULL
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.customBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.myBit >= 2
SET STATISTICS IO OFF;
I see one Constant Scan for the NULL check and 3 table scans for the rest.
t-sql sql-server-2016
If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.
– Learning_DBAdmin
5 hours ago
This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.
– Zikato
4 hours ago
add a comment |
I want to create a table with a NOT NULL bool column.
I use TINYINT with CHECK constraint BETWEEN 0 and 1. The constraint is new and thus trusted
Now I would expect that SQL optimizer now knows that this column can only be 0 and 1 so when I write query col >= 2 I will see Constant Scan in actual execution plan (like when I would when check for NULL or SELECT TOP (0)
But this is not the case, it opts for the table Scan. Do I also need to have index on this column?
In my test below I use TINYINT with CHECK constraint. User Defined Type based on TINYINT with bound RULE and good old BIT.
GO
CREATE TYPE dbo.myBool
FROM [INT] NOT NULL
GO
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
go
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
GO
DROP TABLE IF EXISTS dbo.RuleTest
CREATE TABLE dbo.RuleTest
(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
, oldSchoolBool TINYINT NOT NULL CHECK (oldSchoolBool BETWEEN 0 AND 1)
, customBool dbo.myBool NOT NULL
, myBit BIT NOT NULL
)
;WITH tally (n)
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS a(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS b(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS c(n)
)
INSERT INTO dbo.RuleTest
(oldSchoolBool, customBool, myBit)
SELECT
ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
FROM tally t
SET STATISTICS IO ON;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool IS NULL
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.customBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.myBit >= 2
SET STATISTICS IO OFF;
I see one Constant Scan for the NULL check and 3 table scans for the rest.
t-sql sql-server-2016
I want to create a table with a NOT NULL bool column.
I use TINYINT with CHECK constraint BETWEEN 0 and 1. The constraint is new and thus trusted
Now I would expect that SQL optimizer now knows that this column can only be 0 and 1 so when I write query col >= 2 I will see Constant Scan in actual execution plan (like when I would when check for NULL or SELECT TOP (0)
But this is not the case, it opts for the table Scan. Do I also need to have index on this column?
In my test below I use TINYINT with CHECK constraint. User Defined Type based on TINYINT with bound RULE and good old BIT.
GO
CREATE TYPE dbo.myBool
FROM [INT] NOT NULL
GO
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
go
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
GO
DROP TABLE IF EXISTS dbo.RuleTest
CREATE TABLE dbo.RuleTest
(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
, oldSchoolBool TINYINT NOT NULL CHECK (oldSchoolBool BETWEEN 0 AND 1)
, customBool dbo.myBool NOT NULL
, myBit BIT NOT NULL
)
;WITH tally (n)
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS a(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS b(n)
CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS c(n)
)
INSERT INTO dbo.RuleTest
(oldSchoolBool, customBool, myBit)
SELECT
ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
,ABS(CHECKSUM(NewId())) % 2
FROM tally t
SET STATISTICS IO ON;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool IS NULL
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.customBool >=2
go
SELECT * FROM dbo.RuleTest rt
WHERE rt.myBit >= 2
SET STATISTICS IO OFF;
I see one Constant Scan for the NULL check and 3 table scans for the rest.
t-sql sql-server-2016
t-sql sql-server-2016
asked 7 hours ago
ZikatoZikato
1947
1947
If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.
– Learning_DBAdmin
5 hours ago
This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.
– Zikato
4 hours ago
add a comment |
If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.
– Learning_DBAdmin
5 hours ago
This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.
– Zikato
4 hours ago
If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.
– Learning_DBAdmin
5 hours ago
If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.
– Learning_DBAdmin
5 hours ago
This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.
– Zikato
4 hours ago
This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.
– Zikato
4 hours ago
add a comment |
2 Answers
2
active
oldest
votes
Query 2
The issue is Auto parameterization not trivial plan. Contradiction detection happens as part of simplification before the trivial plan stage (see the Optimization Pipeline diagram here).
In your case the constant 2 gets replaced with a tinyint parameter @1 rather than the literal 2 - as this parameter could have the value 0 or 1 it wouldn't be valid for the query optimiser to assume the check constraint contradicts this.
You can use the following query to get a trivial plan that does use the contradiction detection (the 1=1 prevents the Auto parameterization).
SELECT *
FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2 and 1=1

Query 3
Rules have been deprecated for about 20 years. The CREATE RULE topic states
Rules do not apply to data already existing in the database at the
time the rules are created
So I imagine these are never trusted by the query optimiser as it is possible to do the following and have data that does not adhere to the rule
CREATE TYPE dbo.myBool FROM [INT] NOT NULL
GO
CREATE TABLE dbo.RuleTest
(
customBool dbo.myBool NOT NULL
)
INSERT INTO dbo.RuleTest VALUES (10)
go
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
GO
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
Whilst technically it might be possible to maintain a trusted rule concept analogous to trusted constraints I don't believe this exists.
Query 4
You need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) or equivalent if you want it to do this contradiction detection. Even though a not nullable bit can only hold those two values you don't get this contradiction detected without that
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
add a comment |
Because your query is trivially simple, hitting a 1,000-row table (super low cost), and it's getting trivial optimization.
To get constraint checking, your query needs to get past the trivial optimization phase. One way to do it is to add a subquery:
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
AND 1 = (SELECT 1);
Because the second query bypasses trivial optimization, it gets optimizations for stuff like constraints:

To see when your query is getting trivial optimization, right-click on the SELECT operator in the query plan, and click Properties. In your original queries, the optimization level shows TRIVIAL:

In the real world, trivial optimization queries usually aren't your biggest bottleneck - but when you do see these, not only are constraints getting bypassed, but also index recommendations, indexed view utilization, parallelism, and more.
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
5
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
2
this isn't the correct explanation
– Martin Smith
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
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
);
);
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%2f235172%2fwhy-doesnt-sql-optimizer-use-my-constraint%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Query 2
The issue is Auto parameterization not trivial plan. Contradiction detection happens as part of simplification before the trivial plan stage (see the Optimization Pipeline diagram here).
In your case the constant 2 gets replaced with a tinyint parameter @1 rather than the literal 2 - as this parameter could have the value 0 or 1 it wouldn't be valid for the query optimiser to assume the check constraint contradicts this.
You can use the following query to get a trivial plan that does use the contradiction detection (the 1=1 prevents the Auto parameterization).
SELECT *
FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2 and 1=1

Query 3
Rules have been deprecated for about 20 years. The CREATE RULE topic states
Rules do not apply to data already existing in the database at the
time the rules are created
So I imagine these are never trusted by the query optimiser as it is possible to do the following and have data that does not adhere to the rule
CREATE TYPE dbo.myBool FROM [INT] NOT NULL
GO
CREATE TABLE dbo.RuleTest
(
customBool dbo.myBool NOT NULL
)
INSERT INTO dbo.RuleTest VALUES (10)
go
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
GO
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
Whilst technically it might be possible to maintain a trusted rule concept analogous to trusted constraints I don't believe this exists.
Query 4
You need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) or equivalent if you want it to do this contradiction detection. Even though a not nullable bit can only hold those two values you don't get this contradiction detected without that
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
add a comment |
Query 2
The issue is Auto parameterization not trivial plan. Contradiction detection happens as part of simplification before the trivial plan stage (see the Optimization Pipeline diagram here).
In your case the constant 2 gets replaced with a tinyint parameter @1 rather than the literal 2 - as this parameter could have the value 0 or 1 it wouldn't be valid for the query optimiser to assume the check constraint contradicts this.
You can use the following query to get a trivial plan that does use the contradiction detection (the 1=1 prevents the Auto parameterization).
SELECT *
FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2 and 1=1

Query 3
Rules have been deprecated for about 20 years. The CREATE RULE topic states
Rules do not apply to data already existing in the database at the
time the rules are created
So I imagine these are never trusted by the query optimiser as it is possible to do the following and have data that does not adhere to the rule
CREATE TYPE dbo.myBool FROM [INT] NOT NULL
GO
CREATE TABLE dbo.RuleTest
(
customBool dbo.myBool NOT NULL
)
INSERT INTO dbo.RuleTest VALUES (10)
go
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
GO
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
Whilst technically it might be possible to maintain a trusted rule concept analogous to trusted constraints I don't believe this exists.
Query 4
You need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) or equivalent if you want it to do this contradiction detection. Even though a not nullable bit can only hold those two values you don't get this contradiction detected without that
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
add a comment |
Query 2
The issue is Auto parameterization not trivial plan. Contradiction detection happens as part of simplification before the trivial plan stage (see the Optimization Pipeline diagram here).
In your case the constant 2 gets replaced with a tinyint parameter @1 rather than the literal 2 - as this parameter could have the value 0 or 1 it wouldn't be valid for the query optimiser to assume the check constraint contradicts this.
You can use the following query to get a trivial plan that does use the contradiction detection (the 1=1 prevents the Auto parameterization).
SELECT *
FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2 and 1=1

Query 3
Rules have been deprecated for about 20 years. The CREATE RULE topic states
Rules do not apply to data already existing in the database at the
time the rules are created
So I imagine these are never trusted by the query optimiser as it is possible to do the following and have data that does not adhere to the rule
CREATE TYPE dbo.myBool FROM [INT] NOT NULL
GO
CREATE TABLE dbo.RuleTest
(
customBool dbo.myBool NOT NULL
)
INSERT INTO dbo.RuleTest VALUES (10)
go
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
GO
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
Whilst technically it might be possible to maintain a trusted rule concept analogous to trusted constraints I don't believe this exists.
Query 4
You need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) or equivalent if you want it to do this contradiction detection. Even though a not nullable bit can only hold those two values you don't get this contradiction detected without that
Query 2
The issue is Auto parameterization not trivial plan. Contradiction detection happens as part of simplification before the trivial plan stage (see the Optimization Pipeline diagram here).
In your case the constant 2 gets replaced with a tinyint parameter @1 rather than the literal 2 - as this parameter could have the value 0 or 1 it wouldn't be valid for the query optimiser to assume the check constraint contradicts this.
You can use the following query to get a trivial plan that does use the contradiction detection (the 1=1 prevents the Auto parameterization).
SELECT *
FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2 and 1=1

Query 3
Rules have been deprecated for about 20 years. The CREATE RULE topic states
Rules do not apply to data already existing in the database at the
time the rules are created
So I imagine these are never trusted by the query optimiser as it is possible to do the following and have data that does not adhere to the rule
CREATE TYPE dbo.myBool FROM [INT] NOT NULL
GO
CREATE TABLE dbo.RuleTest
(
customBool dbo.myBool NOT NULL
)
INSERT INTO dbo.RuleTest VALUES (10)
go
CREATE RULE dbo.R_Bool AS @value BETWEEN 0 AND 1
GO
EXEC sys.sp_bindrule @rulename = N'R_Bool'
, @objname = N'myBool'
Whilst technically it might be possible to maintain a trusted rule concept analogous to trusted constraints I don't believe this exists.
Query 4
You need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) or equivalent if you want it to do this contradiction detection. Even though a not nullable bit can only hold those two values you don't get this contradiction detected without that
edited 22 mins ago
answered 1 hour ago
Martin SmithMartin Smith
64.4k10173259
64.4k10173259
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
add a comment |
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
I've tested it and it returns constant scan for the oldSchoolBool, but not the other two (custom type and bit), any reason why? It goes for both your condition )1=1 and Brent's (1 = (SELECT 1))
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?
– Zikato
1 hour ago
add a comment |
Because your query is trivially simple, hitting a 1,000-row table (super low cost), and it's getting trivial optimization.
To get constraint checking, your query needs to get past the trivial optimization phase. One way to do it is to add a subquery:
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
AND 1 = (SELECT 1);
Because the second query bypasses trivial optimization, it gets optimizations for stuff like constraints:

To see when your query is getting trivial optimization, right-click on the SELECT operator in the query plan, and click Properties. In your original queries, the optimization level shows TRIVIAL:

In the real world, trivial optimization queries usually aren't your biggest bottleneck - but when you do see these, not only are constraints getting bypassed, but also index recommendations, indexed view utilization, parallelism, and more.
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
5
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
2
this isn't the correct explanation
– Martin Smith
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
add a comment |
Because your query is trivially simple, hitting a 1,000-row table (super low cost), and it's getting trivial optimization.
To get constraint checking, your query needs to get past the trivial optimization phase. One way to do it is to add a subquery:
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
AND 1 = (SELECT 1);
Because the second query bypasses trivial optimization, it gets optimizations for stuff like constraints:

To see when your query is getting trivial optimization, right-click on the SELECT operator in the query plan, and click Properties. In your original queries, the optimization level shows TRIVIAL:

In the real world, trivial optimization queries usually aren't your biggest bottleneck - but when you do see these, not only are constraints getting bypassed, but also index recommendations, indexed view utilization, parallelism, and more.
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
5
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
2
this isn't the correct explanation
– Martin Smith
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
add a comment |
Because your query is trivially simple, hitting a 1,000-row table (super low cost), and it's getting trivial optimization.
To get constraint checking, your query needs to get past the trivial optimization phase. One way to do it is to add a subquery:
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
AND 1 = (SELECT 1);
Because the second query bypasses trivial optimization, it gets optimizations for stuff like constraints:

To see when your query is getting trivial optimization, right-click on the SELECT operator in the query plan, and click Properties. In your original queries, the optimization level shows TRIVIAL:

In the real world, trivial optimization queries usually aren't your biggest bottleneck - but when you do see these, not only are constraints getting bypassed, but also index recommendations, indexed view utilization, parallelism, and more.
Because your query is trivially simple, hitting a 1,000-row table (super low cost), and it's getting trivial optimization.
To get constraint checking, your query needs to get past the trivial optimization phase. One way to do it is to add a subquery:
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2;
SELECT * FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2
AND 1 = (SELECT 1);
Because the second query bypasses trivial optimization, it gets optimizations for stuff like constraints:

To see when your query is getting trivial optimization, right-click on the SELECT operator in the query plan, and click Properties. In your original queries, the optimization level shows TRIVIAL:

In the real world, trivial optimization queries usually aren't your biggest bottleneck - but when you do see these, not only are constraints getting bypassed, but also index recommendations, indexed view utilization, parallelism, and more.
answered 6 hours ago
Brent OzarBrent Ozar
35.9k19112246
35.9k19112246
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
5
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
2
this isn't the correct explanation
– Martin Smith
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
add a comment |
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
5
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
2
this isn't the correct explanation
– Martin Smith
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
Argh, the one time I don't check for trivialisation.
– Zikato
6 hours ago
5
5
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
No one expects the Spanish Trivialization.
– Brent Ozar
6 hours ago
2
2
this isn't the correct explanation
– Martin Smith
1 hour ago
this isn't the correct explanation
– Martin Smith
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
Sorry, @BrentOzar, I've got to side with Martin. With auto parametrization off I still get a trivial plan that uses the constraint.
– Zikato
1 hour ago
add a comment |
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%2f235172%2fwhy-doesnt-sql-optimizer-use-my-constraint%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
If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.
– Learning_DBAdmin
5 hours ago
This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.
– Zikato
4 hours ago