将 VARCHAR 列隐式转换为 NVARCHAR 不会导致预期的表扫描

SEa*_*986 4 performance datatypes execution-plan type-conversion sql-server-2014

鉴于以下脚本,我可以看到隐式转换和数据类型优先级对查询计划有负面影响

-- create objects
CREATE DATABASE ConvertTest
GO

USE ConvertTest
GO

CREATE TABLE Person
(
    VarcharId   NVARCHAR(4),
    IntId       INT 
)

-- insert data
INSERT INTO Person
SELECT  TOP 1000
        CONVERT(NVARCHAR(4),ROW_NUMBER() OVER (ORDER BY a.object_id)),
        ROW_NUMBER() OVER (ORDER BY a.object_id)
FROM    sys.objects a
        CROSS JOIN sys.objects b

-- create indexes
CREATE INDEX IX_Varchar ON Person
(
    VarcharId,
    IntId   
)

CREATE INDEX IX_Int ON Person
(
    IntId,
    VarcharId
)

DECLARE @id NVARCHAR(4) = 100
-- statement 1
SELECT * FROM Person WHERE VarcharId = @id
-- index seek

-- statement 2
SELECT * FROM Person WHERE IntId = @id
-- index seek
GO

DECLARE @id INT = 100

-- statement 3
SELECT * FROM Person WHERE VarcharId = @id
-- index scan

-- statement 4
SELECT * FROM Person WHERE IntId = @id
-- index seek
Run Code Online (Sandbox Code Playgroud)

查询 3 将 VarcharId 列隐式转换为 int(具有更高的优先级),这会导致谓词不可 SARGable,从而导致表扫描。

然而,当我运行类似的测试时,我没有得到我预期的结果:

-- create objects
CREATE DATABASE ConvertTest2
GO

USE ConvertTest2
GO

CREATE TABLE Ids
(
    NvarId  NVARCHAR(4),
    VarId   VARCHAR(4)
)


-- insert data
INSERT INTO Ids
SELECT  TOP 1000
        CONVERT(NVARCHAR(4),ROW_NUMBER() OVER (ORDER BY a.object_id)),
        CONVERT(VARCHAR(4),ROW_NUMBER() OVER (ORDER BY a.object_id))
FROM    sys.objects a
        CROSS JOIN sys.objects b

-- create indexes
CREATE INDEX IX_NvarId ON Ids
(
    NvarId,
    VarId
)

CREATE INDEX IX_VarId ON Ids
(
    VarId,
    NvarId
)

DECLARE @id NVARCHAR(4) = N'10'
SELECT * FROM Ids WHERE NvarId = @id
SELECT * FROM Ids WHERE VarId = @id
GO

DECLARE @id VARCHAR(4) = '10'
SELECT * FROM Ids WHERE NvarId = @id
SELECT * FROM Ids WHERE VarId = @id
Run Code Online (Sandbox Code Playgroud)

所有四个查询都显示索引查找(尽管查询二通过计算机标量的嵌套循环运行查找)

鉴于 NVARCHAR 的数据类型优先级高于 VARCHAR,我预计会看到 VarId 列隐式转换为 VARCHAR,从而导致表扫描。

在 varchar / nvarchar 类型之间转换时,数据类型优先级为何/如何不同?

SEa*_*986 5

自从我发帖以来,我已经成功地在这里找到了答案。

对谓词中的列执行从 VARCHAR 到 NVARCHAR 的隐式转换时,是否执行扫描或查找的行为取决于排序规则设置。

较旧的旧排序规则设置将导致索引扫描,而较新的排序规则设置将导致查找