IN() 条件是否始终是相等搜索?

Min*_*NCH 5 index sql-server index-tuning

我试图了解在索引方面 IN() 条件是相等还是不等搜索。

我一直在互联网上寻找答案,发现的答案多种多样,是的,这是一个平等搜索,不,这不是一个平等搜索,有时它是一个平等搜索。

即,有些人建议如果条件中有一个值,则它是相等搜索,如果您有超过一个值,则它会变成不等式搜索,但我也发现与建议它始终相等的答案相矛盾。

注意:我使用 SQL Server 作为 DBMS,因为我不确定它们之间是否有所不同。

编辑:如果是这样,我可能会感到困惑,抱歉,但是当您创建索引时,您不需要了解使用该索引完成的搜索在搜索时是否将使用相等或不等参数。因此,您将设计索引,使其始终首先查找相等匹配。我更关心的是,当涉及到对索引进行查找时,SQL“引擎”是否会将其视为相等搜索。正如我所读到的,有时不会。

SQL Server“引擎”会将 IN() 操作视为等式,除非它认为可以通过将其视为不等式来加速查询,然后查看执行计划,它可能会忽略已设置的索引并将寻找不等式。

首先,这是正确的吗?其次,我试图了解在什么情况下会发生这种情况。

Eri*_*ing 8

但是并且但是不是

IN运算符通常被视为索引上的相等搜索,但并不总是产生与相等搜索相同的保证。

假设我们有这个索引:

CREATE INDEX
    v
ON dbo.Votes
(
    VoteTypeId,
    PostId,
    CreationDate
)
WITH 
(
    SORT_IN_TEMPDB = ON, 
    DATA_COMPRESSION = PAGE
);
Run Code Online (Sandbox Code Playgroud)

它非常适合对 进行相等搜索VoteTypeId,并为PostId和提供排序数据CreationDate

我们可以通过这样的查询来证明这一点:

SELECT
    x.*
FROM
(
    SELECT
        r = 
            ROW_NUMBER() OVER
            (
                PARTITION BY
                    v.PostId
                ORDER BY
                    v.CreationDate
            )
    FROM dbo.Votes AS v
    WHERE v.VoteTypeId = 1
) AS x
WHERE x.r = 0;
Run Code Online (Sandbox Code Playgroud)

查询计划将如下所示:

坚果

通过在我们的索引中查找单个值。

现在进行这个查询,它使用IN

SELECT
    x.*
FROM
(
    SELECT
        r = 
            ROW_NUMBER() OVER
            (
                PARTITION BY
                    v.PostId
                ORDER BY
                    v.CreationDate
            )
    FROM dbo.Votes AS v
    WHERE v.VoteTypeId IN (1, 2)
) AS x
WHERE x.r = 0;
Run Code Online (Sandbox Code Playgroud)

查询计划现在看起来有点不同。尽管我们仍然使用两个谓词作为相等搜索来查找索引,但现在我们需要一个排序运算符来支持窗口函数。

坚果

排序运算符将PostIdCreationDateROW_NUMBER开窗函数查找的顺序排列。

坚果

查询可以像这样重写,以也使用多个相等谓词并保留索引的排序保证:

SELECT
    x.*
FROM
(
    SELECT
        r = 
            ROW_NUMBER() OVER
            (
                PARTITION BY
                    v.PostId
                ORDER BY
                    v.CreationDate
            )
    FROM 
    (
        SELECT
            v.*
        FROM dbo.Votes AS v
        WHERE v.VoteTypeId = 1
        
        UNION ALL
        
        SELECT
            v.*
        FROM dbo.Votes AS v
        WHERE v.VoteTypeId = 2
    ) AS v
) AS x
WHERE x.r = 0;
Run Code Online (Sandbox Code Playgroud)

查询计划回到之前的状态,不需要排序运算符:

坚果

无论如何,我通常看到IN转换为多个OR谓词的情况是当周围没有有用的索引时。情况并非总是如此,但马蹄铁和手榴弹似乎与查询优化器有很多共同点。

SELECT
    x.*
FROM
(
    SELECT
        r = 
            ROW_NUMBER() OVER
            (
                PARTITION BY
                    v.PostId
                ORDER BY
                    v.CreationDate
            )
    FROM dbo.Votes AS v
    WHERE v.UserId IN 
         (
             1, 2, 3, 4, 5, 6, 7, 8, 9,
             10, 11, 12, 13, 15, 16
         )
) AS x
WHERE x.r = 0;
Run Code Online (Sandbox Code Playgroud)

VoteTypeId我们不是在 上搜索,而是在 上UserId搜索,除了作为聚集索引的一部分之外,它没有被索引,它不是键列,因此不以任何方式排序。

坚果

有关更多详细信息,请参阅我的帖子:


Tib*_*szi 5

IN 是等式搜索,而 NOT IN 是不等式搜索。或者,更具体地说,举个例子:

对于IN:

WHERE p.Color IN('Yellow', 'Blue')
Run Code Online (Sandbox Code Playgroud)

上式可变形为:

WHERE p.Color = 'Yellow' OR p.Color = 'Blue'
Run Code Online (Sandbox Code Playgroud)

对于不在:

WHERE p.Color NOT IN('Yellow', 'Blue')
Run Code Online (Sandbox Code Playgroud)

上式可变形为:

WHERE p.Color <> 'Yellow' AND p.Color <> 'Blue'
Run Code Online (Sandbox Code Playgroud)

例如,SQL Server 可以对您要搜索的每个值的 IN 子句使用索引,并返回所有这些值。