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

Generate an RGB colour grid

Can an alien society believe that their star system is the universe?

Multiple OR (||) Conditions in If Statement

What's the meaning of "fortified infraction restraint"?

Take 2! Is this homebrew Lady of Pain warlock patron balanced?

Trademark violation for app?

Do wooden building fires get hotter than 600°C?

How to tell that you are a giant?

A term for a woman complaining about things/begging in a cute/childish way

If windows 7 doesn't support WSL, then what does Linux subsystem option mean?

How could we fake a moon landing now?

How does light 'choose' between wave and particle behaviour?

As a beginner, should I get a Squier Strat with a SSS config or a HSS?

Amount of permutations on an NxNxN Rubik's Cube

Is grep documentation about ignoring case wrong, since it doesn't ignore case in filenames?

Why do we bend a book to keep it straight?

How does the math work when buying airline miles?

What is the effect of altitude on true airspeed?

What is the font for "b" letter?

Is there any word for a place full of confusion?

How come Sam didn't become Lord of Horn Hill?

Is there hard evidence that the grant peer review system performs significantly better than random?

SF book about people trapped in a series of worlds they imagine

Dating a Former Employee



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;








3















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.










share|improve this question






















  • If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.

    – Learning_DBAdmin
    4 hours ago











  • This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.

    – Zikato
    3 hours ago

















3















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.










share|improve this question






















  • If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.

    – Learning_DBAdmin
    4 hours ago











  • This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.

    – Zikato
    3 hours ago













3












3








3








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.










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 6 hours ago









ZikatoZikato

1847




1847












  • If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.

    – Learning_DBAdmin
    4 hours ago











  • This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.

    – Zikato
    3 hours ago

















  • If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.

    – Learning_DBAdmin
    4 hours ago











  • This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.

    – Zikato
    3 hours ago
















If you want to use as a boolean type then why tinyint in sql server, you may use BIT datatype.

– Learning_DBAdmin
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
4 hours ago













This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.

– Zikato
3 hours ago





This is theoretical, also there can be reasons for not using a bit, like calculations or aggregations.

– Zikato
3 hours ago










2 Answers
2






active

oldest

votes


















4














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


enter image description here






share|improve this answer

























  • 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
    28 mins ago











  • @Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

    – Martin Smith
    26 mins ago












  • @MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

    – Zikato
    20 mins ago






  • 1





    Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

    – Martin Smith
    14 mins ago


















4














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:



Execution plans



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:



Trivial optimization



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.






share|improve this answer























  • Argh, the one time I don't check for trivialisation.

    – Zikato
    5 hours ago






  • 5





    No one expects the Spanish Trivialization.

    – Brent Ozar
    5 hours ago






  • 1





    this isn't the correct explanation

    – Martin Smith
    41 mins 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
    18 mins ago











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
);



);













draft saved

draft discarded


















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









4














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


enter image description here






share|improve this answer

























  • 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
    28 mins ago











  • @Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

    – Martin Smith
    26 mins ago












  • @MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

    – Zikato
    20 mins ago






  • 1





    Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

    – Martin Smith
    14 mins ago















4














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


enter image description here






share|improve this answer

























  • 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
    28 mins ago











  • @Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

    – Martin Smith
    26 mins ago












  • @MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

    – Zikato
    20 mins ago






  • 1





    Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

    – Martin Smith
    14 mins ago













4












4








4







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


enter image description here






share|improve this answer















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


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited 12 mins ago

























answered 41 mins 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
    28 mins ago











  • @Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

    – Martin Smith
    26 mins ago












  • @MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

    – Zikato
    20 mins ago






  • 1





    Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

    – Martin Smith
    14 mins 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
    28 mins ago











  • @Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

    – Martin Smith
    26 mins ago












  • @MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

    – Zikato
    20 mins ago






  • 1





    Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

    – Martin Smith
    14 mins 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
28 mins 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
28 mins ago













@Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

– Martin Smith
26 mins ago






@Zikato - rules were deprecated a long time ago. At least in SQL Server 2000 era. I have no idea whether the Query Optimiser ever uses contradiction detection for those. I've been using SQL Server for about 20 years and never used them as they were deprecated before I started with it!

– Martin Smith
26 mins ago














@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

– Zikato
20 mins ago





@MarinSmith Rules are the stuff of the myths, but very much real on some production servers. And the Bit?

– Zikato
20 mins ago




1




1





Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

– Martin Smith
14 mins ago





Yep you need to add a redundant check constraint on CHECK (myBit BETWEEN 0 AND 1) 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

– Martin Smith
14 mins ago













4














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:



Execution plans



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:



Trivial optimization



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.






share|improve this answer























  • Argh, the one time I don't check for trivialisation.

    – Zikato
    5 hours ago






  • 5





    No one expects the Spanish Trivialization.

    – Brent Ozar
    5 hours ago






  • 1





    this isn't the correct explanation

    – Martin Smith
    41 mins 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
    18 mins ago















4














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:



Execution plans



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:



Trivial optimization



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.






share|improve this answer























  • Argh, the one time I don't check for trivialisation.

    – Zikato
    5 hours ago






  • 5





    No one expects the Spanish Trivialization.

    – Brent Ozar
    5 hours ago






  • 1





    this isn't the correct explanation

    – Martin Smith
    41 mins 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
    18 mins ago













4












4








4







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:



Execution plans



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:



Trivial optimization



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.






share|improve this answer













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:



Execution plans



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:



Trivial optimization



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.







share|improve this answer












share|improve this answer



share|improve this answer










answered 6 hours ago









Brent OzarBrent Ozar

35.9k19112246




35.9k19112246












  • Argh, the one time I don't check for trivialisation.

    – Zikato
    5 hours ago






  • 5





    No one expects the Spanish Trivialization.

    – Brent Ozar
    5 hours ago






  • 1





    this isn't the correct explanation

    – Martin Smith
    41 mins 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
    18 mins ago

















  • Argh, the one time I don't check for trivialisation.

    – Zikato
    5 hours ago






  • 5





    No one expects the Spanish Trivialization.

    – Brent Ozar
    5 hours ago






  • 1





    this isn't the correct explanation

    – Martin Smith
    41 mins 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
    18 mins ago
















Argh, the one time I don't check for trivialisation.

– Zikato
5 hours ago





Argh, the one time I don't check for trivialisation.

– Zikato
5 hours ago




5




5





No one expects the Spanish Trivialization.

– Brent Ozar
5 hours ago





No one expects the Spanish Trivialization.

– Brent Ozar
5 hours ago




1




1





this isn't the correct explanation

– Martin Smith
41 mins ago





this isn't the correct explanation

– Martin Smith
41 mins 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
18 mins 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
18 mins ago

















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Ружовы пелікан Змест Знешні выгляд | Пашырэнне | Асаблівасці біялогіі | Літаратура | НавігацыяДагледжаная версіяправерана1 зменаДагледжаная версіяправерана1 змена/ 22697590 Сістэматыкана ВіківідахВыявына Вікісховішчы174693363011049382

ValueError: Error when checking input: expected conv2d_13_input to have shape (3, 150, 150) but got array with shape (150, 150, 3)2019 Community Moderator ElectionError when checking : expected dense_1_input to have shape (None, 5) but got array with shape (200, 1)Error 'Expected 2D array, got 1D array instead:'ValueError: Error when checking input: expected lstm_41_input to have 3 dimensions, but got array with shape (40000,100)ValueError: Error when checking target: expected dense_1 to have shape (7,) but got array with shape (1,)ValueError: Error when checking target: expected dense_2 to have shape (1,) but got array with shape (0,)Keras exception: ValueError: Error when checking input: expected conv2d_1_input to have shape (150, 150, 3) but got array with shape (256, 256, 3)Steps taking too long to completewhen checking input: expected dense_1_input to have shape (13328,) but got array with shape (317,)ValueError: Error when checking target: expected dense_3 to have shape (None, 1) but got array with shape (7715, 40000)Keras exception: Error when checking input: expected dense_input to have shape (2,) but got array with shape (1,)

Illegal assignment from SObject to ContactFetching String, Id from Map - Illegal Assignment Id to Field / ObjectError: Compile Error: Illegal assignment from String to BooleanError: List has no rows for assignment to SObjectError on Test Class - System.QueryException: List has no rows for assignment to SObjectRemote action problemDML requires SObject or SObject list type error“Illegal assignment from List to List”Test Class Fail: Batch Class: System.QueryException: List has no rows for assignment to SObjectMapping to a user'List has no rows for assignment to SObject' Mystery