一尘不染

<> 和 != 在 SQL Server 中的性能相同的权威来源

sql

考虑一下这个关于 SO 的答案,它可以让询问者对<>运营商感到放心:

<>是……和……一样!=

但随后一位评论者说:

确实,它们在功能上是相同的。但是,SQL 优化器如何使用它们却大不相同。=/!= 被简单地评估为真/假,而 <> 意味着引擎必须查看该值是大于还是小于,这意味着更多的性能开销。只是在编写可能很昂贵的查询时要考虑的事情。

我相信这是错误的,但为了解决潜在的怀疑论者,我想知道是否有人可以提供权威或规范的来源来证明这些运算符不仅在功能上相同,而且在所有方面都相同?


阅读 80

收藏
2022-10-25

共1个答案

一尘不染

在解析期间,SQL Server 调用sqllang!DecodeCompOp以确定存在的比较运算符的类型:

调用堆栈

这发生在优化器中的任何内容涉及之前。

比较运算符 (Transact-SQL)

比较运算符和含义

使用调试器和公共符号跟踪代码,sqllang!DecodeCompOp在寄存器eax* 中返回一个值,如下所示:

╔════╦══════╗
║ Op ║ Code ║
╠════╬══════╣
║ <  ║    1 ║
║ =  ║    2 ║
║ <= ║    3 ║
║ !> ║    3 ║
║ >  ║    4 ║
║ <> ║    5 ║
║ != ║    5 ║
║ >= ║    6 ║
║ !< ║    6 ║
╚════╩══════╝

!=并且<>都返回 5,因此在所有后续操作(包括编译和优化)中都无法区分。


虽然次要于上述点,但也可以(例如,使用未记录的跟踪标志 8605)查看传递给优化器的逻辑树以确认两者!=<>映射到ScaOp_Comp x_cmpNe(不等于标量运算符比较)。

例如:

SELECT P.ProductID FROM Production.Product AS P
WHERE P.ProductID != 4
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);

SELECT P.ProductID FROM Production.Product AS P
WHERE P.ProductID <> 4
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);

两者都产生:

LogOp_Project QCOL: [P].ProductID
    LogOp_Select
        LogOp_Get TBL:Production.Product(别名 TBL:P)
        ScaOp_Comp x_cmpNe
            ScaOp_Identifier QCOL:[P].ProductID
            ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=4)
    AncOp_PrjList
2022-10-25