Ich möchte eine Tabelle mit einer NOT NULL
Bool-Spalte erstellen .
Ich benutze TINYINT
mit CHECK
Zwang BETWEEN 0 and 1
. Die Einschränkung ist neu und daher vertrauenswürdig
Jetzt würde ich erwarten, dass SQL Optimizer jetzt weiß, dass diese Spalte nur 0 und 1 sein kann. Wenn ich also eine Abfrage schreibe, col >= 2
wird Constant Scan im tatsächlichen Ausführungsplan angezeigt (wie wenn ich nach NULL
oder suchen würdeSELECT TOP (0)
Dies ist jedoch nicht der Fall, sondern entscheidet sich für die Tabelle Scan. Muss ich auch einen Index für diese Spalte haben?
In meinem Test unten verwende ich TINYINT
mit CHECK
Einschränkung. Benutzerdefinierter Typ basierend auf TINYINT
gebundenem RULE
und gutem Alter 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;
Ich sehe einen konstanten Scan für die NULL-Prüfung und 3 Tabellenscans für den Rest.
quelle
WHERE myBit >= 2
Bedingungen haben , wenn Sie wissen, dass die Werte niemals größer als 1 sein können.Antworten:
Abfrage 2
Das Problem ist die automatische Parametrisierung .
In Ihrem Fall wird die Konstante
2
durch einen tinyint-Parameter@1
anstelle des Literal ersetzt,2
da dieser Parameter den Wert haben könnte0
oder1
es für den Abfrageoptimierer nicht gültig wäre, anzunehmen, dass die Prüfbedingung dem widerspricht.Mit der folgenden Abfrage können Sie einen Plan abrufen, der die Widersprüchlichkeitserkennung verwendet (dies
1=1
verhindert die automatische Parametrisierung). Die Widersprüchlichkeitserkennung erfolgt dann im Rahmen der Vereinfachung (siehe das Diagramm der Optimierungspipeline hier).Der resultierende Plan wird zu einem konstanten Scan vereinfacht
Abfrage 3
Regeln werden seit ungefähr 20 Jahren entmutigt / veraltet. 2000 BOL beschreibt sie als
Das
CREATE RULE
Thema besagtDaher stelle ich mir vor, dass diese vom Abfrageoptimierer niemals als vertrauenswürdig eingestuft werden, da Folgendes möglich ist und Daten vorliegen, die nicht der Regel entsprechen
Obwohl es technisch möglich sein könnte, ein vertrauenswürdiges Regelkonzept analog zu vertrauenswürdigen Einschränkungen beizubehalten, glaube ich nicht, dass dies existiert.
Abfrage 4
Sie müssen eine redundante Prüfeinschränkung
CHECK (myBit BETWEEN 0 AND 1)
oder eine gleichwertige hinzufügen, wenn Sie möchten, dass diese Widersprüche erkannt wird. Obwohl ein nicht nullbares Bit nur diese beiden Werte enthalten kann, wird dieser Widerspruch ohne diesen nicht erkanntquelle