当前位置: 首页 > 面试题库 >

不存在vs不存在

鲁永福
2023-03-14
问题内容

这些查询中哪个更快?

不存在:

SELECT ProductID, ProductName 
FROM Northwind..Products p
WHERE NOT EXISTS (
    SELECT 1 
    FROM Northwind..[Order Details] od 
    WHERE p.ProductId = od.ProductId)

或不在:

SELECT ProductID, ProductName 
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
    SELECT ProductID 
    FROM Northwind..[Order Details])

查询执行计划说他们都做同样的事情。如果是这样,建议使用哪种形式?

这基于NorthWind数据库。


问题答案:

我始终默认为NOT EXISTS。

目前执行计划可能是相同的,但是如果将来更改任一列以允许NULLs,则该NOT IN版本将需要做更多的工作(即使NULL数据中实际上没有s),并且NOT INifNULL的语义也存在。无论如何都不太可能成为您想要的。

如果没有Products.ProductID或[Order Details].ProductID允许NULLS中的NOT IN将被同等对待下面的查询。

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId) 

确切的计划可能会有所不同,但是对于我的示例数据,我得到了以下内容。

一个合理的普遍误解似乎是与联接相比,相关的子查询总是“不好的”。当他们强制执行嵌套循环计划(逐行评估子查询)时,肯定会出现这种情况,但是该计划包括反半联接逻辑运算符。反半联接不限于嵌套循环,还可以使用哈希或合并(如本例所示)联接。

/*Not valid syntax but better reflects the plan*/ 
SELECT p.ProductID,
       p.ProductName
FROM   Products p
       LEFT ANTI SEMI JOIN [Order Details] od
         ON p.ProductId = od.ProductId 

如果[Order Details].ProductID为NULL-able,则查询变为

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL) 

原因是正确的语义if如果[Order Details]包含any NULL ProductId,则不返回任何结果。请参阅额外的反半连接和行计数假脱机,以验证是否已将其添加到计划中。

如果Products.ProductID还更改为变为NULL-able,则查询变为

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL)
       AND NOT EXISTS (SELECT *
                       FROM   (SELECT TOP 1 *
                               FROM   [Order Details]) S
                       WHERE  p.ProductID IS NULL) 

其原因之一是因为NULL Products.ProductId不应该在返回的结果只是如果NOT IN子查询是在所有返回任何结果(即[Order Details]表是空的)。在这种情况下应该。在我的样本数据计划中,这是通过添加另一个反半联接来实现的,如下所示。

在Buckley已经链接的博客中可以看到这样的效果。在该示例中,逻辑读取的数量从大约400增加到500,000。

另外,单个NULL可以将行计数减少到零的事实使基数估计非常困难。如果SQL Server假定会发生这种情况,但实际上NULL数据中没有行,则执行计划的其余部分可能会灾难性地恶化,如果这只是较大查询的一部分,并且嵌套循环不当会导致重复执行昂贵的子程序例如树。

但是,这不是-able列NOT IN上唯一可行的执行计划NULL。本文显示了另一个针对AdventureWorks2008数据库的查询。

对于NOT INonNOT NULL列或NOT EXISTS针对null列或non nullable列的,给出以下计划。

当列更改为NULL-able时,该NOT IN计划现在看起来像

它为计划添加了一个额外的内部联接运算符。这里说明该装置。只需要将先前的单个相关索引搜索转换为Sales.SalesOrderDetail.ProductID = <correlated_product_id>每个外行两个搜索。另一个打开WHERE Sales.SalesOrderDetail.ProductID IS NULL

由于这是在反半联接下,如果该联接返回任何行,则不会发生第二次寻道。但是,如果Sales.SalesOrderDetail不包含任何NULL ProductIDs,它将使所需的查找操作次数增加一倍。



 类似资料:
  • 我已经建立了一个Spark and Flink k-means应用程序。我的测试用例是一个3节点集群上的100万个点的集群。 当内存瓶颈开始时,Flink开始外包给磁盘,工作缓慢,但工作正常。然而,如果内存已满,Spark将失去执行器,并再次启动(无限循环?)。 我尝试在邮件列表的帮助下自定义内存设置,谢谢。但是火花仍然不起作用。 是否需要设置任何配置?我是说Flink的记忆力很差,斯帕克也必须能

  • 问题内容: 想知道是否有人可以通过此查询为我提供一些帮助: 我只想得到计数(已重命名)等于1的结果。此查询出现错误: 但是该列 应该 存在,对吗?有人可以协助吗?谢谢! 问题答案: 您不能在WHERE子句中引用列别名。 在传统SQL中,最早可以引用列别名的是子句。但是MySQL和SQL Server允许在and子句中进行访问。

  • 问题内容: 在golang中,有没有办法查看是否可以将解编入结构的json字段与设置为null的json字段区分开?因为两者都将struct中的值设置为nil,但是我需要知道字段是否以该字段开头,并查看是否有人将其设置为null。 VS 当解组为结构时,两个json均为零。任何有用的资源将不胜感激! 问题答案: 使用以“拖延”解组过程决定做某件事之前要确定原始字节: 参观游乐场https://pl

  • 问题内容: 我认为我要沿着这条路走正确的路…请忍受,因为我的SQL并不是最出色的 我试图查询数据库以从一个表中选择所有单元格中某些单元格不存在的所有内容。那没有多大意义,但我希望这段代码会 因此,基本上我有一张桌子,上面列出了员工及其详细信息。然后是另一个表,其中包含一些其他详细信息,包括其名称。在eotm_dyn表中没有名称的地方,这意味着它们没有条目,我想确切地知道它们是谁,或者换句话说,确切

  • 我正在研究如何从命令行编译Java。我得到的是: 我得到的是: HelloWorld: inner.java 内部2.Java 我正在用编译这个文件,这个文件工作得很好。 现在我的理解是,因为helloworld.java在它的import语句中引用了其他包,所以javac会去编译这些包。我猜对于所有的Java包,javac在内部都有。 反正-如果我在helloworld.java中添加以下导入行

  • 我得到了一个可怕的软件包,它根本不存在,简直要了我的命。代码很好,我在市场上有运行代码的应用程序。 现在它正在影响简单的应用程序。o.0 <代码>R.string。app_name是错误的my 。应该对应于R.java