4

我刚刚(昨天)学会了使用“exists”而不是“in”。

 BAD
 select * from table where nameid in ( 
          select nameid from othertable where otherdesc =  'SomeDesc' )      
 GOOD
 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      

我对此有一些疑问:

1)我理解的解释是:“这样做更好的原因是因为只会返回匹配的值,而不是构建大量可能的结果列表”。这是否意味着虽然第一个子查询可能返回 900 个结果,但第二个子查询将只返回 1(是或否)?

2)过去我曾抱怨过RDBMS:“只能检索前1000行”,第二种方法可以解决这个问题吗?

3)第二个子查询中别名的范围是什么?...别名是否只存在于括号中?

例如

 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      
 AND 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeOtherDesc' )      

也就是说,如果我在第二个“存在”中使用相同的别名( o 代表其他表),它会与第一个存在有什么问题吗?还是他们完全独立?

这是 Oracle 唯一相关的东西还是对大多数 RDBMS 有效?

非常感谢

4

5 回答 5

4

它特定于每个 DBMS,并取决于查询优化器。一些优化器检测 IN 子句并翻译它。

在我测试的所有 DBMS 中,别名仅在 ( ) 内有效

顺便说一句,您可以将查询重写为:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc');

并且,回答您的问题:

  1. 是的
  2. 是的
  3. 是的
于 2008-10-09T19:36:03.113 回答
3

您正在涉足复杂的领域,称为“相关子查询”。由于我们没有关于您的表格和关键结构的详细信息,因此某些答案只能是“可能”。

在您的初始 IN 查询中,无论 OtherTable 是否包含列 NameID (实际上,OtherDesc 是否作为 Table 或 OtherTable 中的列存在 - 这在您的任何示例中都不清楚,但可能是列其他表)。这种行为是使相关子查询成为相关子查询的原因。当人们第一次遇到它时,它也是一种常规的焦虑来源——总是偶然的。由于 SQL 标准要求将子查询中的名称解释为引用外部查询中的列,如果子查询中提到的表中没有具有相关名称的列,但存在具有外部(主)查询中提到的表中的相关名称,

您的 Q1 的答案是“取决于情况”,但给出合理的假设(NameID 作为两个表中的列存在;OtherDesc 仅存在于 OtherTable 中),就返回的数据集而言,结果应该是相同的,但可能不是在性能方面相当。

Q2 的答案是,在过去,如果没有缺陷,您使用的是劣质的 DBMS。如果它支持 EXISTS,那么 DBMS 可能仍然会抱怨结果的基数。

应用于第一个 EXISTS 查询的 Q3 的答案是“t 在整个语句中可用作别名,但 o 仅可用作括号内的别名”。应用于您的第二个示例框 - 使用 AND 连接两个子选择(当我查看第二个子选择时,其中第二个缺少左括号),然后 "t 在整个语句中可用作别名并引用相同表,但有两个不同的别名都标记为“o”,每个子查询一个”。请注意,如果 OtherDesc 对于 OtherTable 中的给定 NameID 值是唯一的,则查询可能不会返回任何数据;否则,它需要 OtherTable 中具有相同 NameID 的两行以及 Table 中具有该 NameID 值的每一行的两个 OtherDesc 值。

于 2008-10-09T21:20:30.767 回答
2
  1. 特定于 Oracle:当您使用 IN 子句编写查询时,您是在告诉基于规则的优化器您希望内部查询驱动外部查询。当您在 where 子句中编写 EXISTS 时,您是在告诉优化器您希望首先运行外部查询,并使用每个值从内部查询中获取一个值。请参阅 “子查询中 IN 和 EXISTS 之间的区别”
  2. 大概。
  3. 在子查询中声明的别名存在于子查询中。顺便说一句,我认为您的带有 2 个 AND 子查询的示例不是有效的 SQL。您的意思是 UNION 而不是 AND?
于 2008-10-09T19:47:22.343 回答
1

就个人而言,我会为此使用联接,而不是子查询。

SELECT t.*
FROM yourTable t
    INNER JOIN otherTable ot
        ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')
于 2008-10-09T19:36:27.577 回答
1

很难概括 EXISTS 总是比 IN 好。从逻辑上讲,如果是这样的话,那么 SQL 社区会用 EXISTS 代替 IN ......另外,请注意 IN 和 EXISTS 是不一样的,当你使用两者时结果可能会不同......

使用 IN,通常它会在不删除 NULL 的情况下对内部表进行一次全表扫描(因此,如果您的内部表中有 NULL,IN 默认情况下不会删除 NULLS)......而 EXISTS 删除 NULL 并且在相关子查询的情况下,它对来自外部查询的每一行运行内部查询。

假设没有 NULLS 并且它是一个简单的查询(没有相关性),如果您找到的行不是最后一行,则 EXIST 可能会执行得更好。如果它恰好是最后一行,EXISTS 可能需要像 IN 一样扫描到最后......所以类似的性能......

但是 IN 和 EXISTS 不可互换...

于 2013-08-21T05:13:46.977 回答