Zik*_*ato 7 t-sql sql-server-2016
我想创建一个带有NOT NULLbool 列的表。
我用TINYINT与CHECK约束BETWEEN 0 and 1。约束是新的,因此是可信的
现在我希望 SQL 优化器现在知道这个列只能是 0 和 1,所以当我写查询时,col >= 2我会在实际执行计划中看到常量扫描(就像我在检查NULL或SELECT TOP (0)
但事实并非如此,它选择了表扫描。我还需要在此列上建立索引吗?
在我下面的测试中,我使用TINYINT了CHECK约束。用户定义类型基于TINYINTwith boundRULE和 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;
Run Code Online (Sandbox Code Playgroud)
我看到 NULL 检查进行了一次常量扫描,其余部分进行了 3 次表扫描。
Mar*_*ith 11
查询 2
问题是自动参数化。
在您的情况下,常量2被替换为 tinyint 参数@1而不是文字2- 因为此参数可能具有值,0否则1查询优化器假设检查约束与此矛盾是无效的。
您可以使用以下查询来获取使用矛盾检测的计划(1=1防止自动参数化)矛盾检测然后作为简化的一部分发生(请参阅此处的优化管道图)。
SELECT *
FROM dbo.RuleTest rt
WHERE rt.oldSchoolBool >=2 and 1=1
Run Code Online (Sandbox Code Playgroud)
结果计划被简化为持续扫描
查询 3
大约 20 年来,不鼓励/弃用规则。2000 BOL 将它们描述为
向后兼容功能...... CHECK 约束是首选的标准方式
该CREATE 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'
Run Code Online (Sandbox Code Playgroud)
虽然从技术上讲,有可能维护类似于受信任约束的受信任规则概念,但我认为这不存在。
查询 4
CHECK (myBit BETWEEN 0 AND 1)如果您希望它执行此矛盾检测,则需要在或等效项上添加冗余检查约束。即使一个不可为空的位只能保存这两个值,你也不会在没有它的情况下检测到这个矛盾
| 归档时间: |
|
| 查看次数: |
309 次 |
| 最近记录: |