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

Eri*_*ikE 83 performance sql-server operator

考虑一下SO 上的这个答案,它使询问者对<>运营商感到放心:

<>是 ... 与 相同!=

但随后一位评论者插嘴说:

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

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

Pau*_*ite 156

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

调用栈

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

比较运算符 (Transact-SQL)

比较运算符和含义

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

?????????????
? Op ? Code ?
?????????????
? <  ?    1 ?
? =  ?    2 ?
? <= ?    3 ?
? !> ?    3 ?
? >  ?    4 ?
? <> ?    5 ?
? != ?    5 ?
? >= ?    6 ?
? !< ?    6 ?
?????????????
Run Code Online (Sandbox Code Playgroud)

!=并且<>都返回 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);
Run Code Online (Sandbox Code Playgroud)

两者都产生:

LogOp_Project QCOL: [P].ProductID
    日志操作选择
        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 

脚注

* 我使用WinDbg;其他调试器可用。公共符号可通过通常的 Microsoft 符号服务器获得。有关详细信息,请参阅SQL Server 客户咨询团队使用 Minidump 深入了解 SQL Server使用 WinDbg 进行 SQL Server 调试 – Klaus Aschenbrenner的介绍

** 在 32 位 Intel 衍生产品上使用 EAX 来获取函数的返回值是很常见的。当然,Win32 ABI 就是这样做的,我很确定它继承了旧的 MS-DOS 时代的做法,当时 AX 用于相同的目的 - Michael Kjörling


sta*_*ray 64

我在 Microsoft 的 SQL 支持部门工作,我问过 SQL Server 性能的高级升级工程师和主题专家 Jack Li,“SQL 对待 != 与 <> 有什么不同吗?” 他说:“他们是一样的。”


a1e*_*x07 8

我认为以下证明<>没有进行 2 次比较。

  1. SQL 标准 92 定义<>为不等于运算符 ( http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt )。从技术上讲,!=是标准的扩展(即使我想不出任何不实现它的 RDBMS)。
  2. 如果 SQLServer 将其<>视为 2 个运算符,而不是一个运算符,则它会执行相同的操作,><这实际上是语法错误。