EXISTS 真的比IN 快吗?

当我们在网络上搜索EXISTS和IN时,总能搜索到推荐使用EXISTS而不建议使用IN的说法,说的头头是道,让人觉得就不该使用IN。但事实真的如此吗?我们不妨做

大家好,今天小编来为大家解答EXISTS 真的比IN 快吗?这个问题,很多人还不知道,现在让我们一起来看看吧!

接下来我们来验证一下对于NULL值和一般数据来说IN、EXISTS、NOT IN、NOT EXISTS是否有区别。因此,我们需要准备一些数据。我们需要一个名为DEMO_WYDXBG 的表。表中数据如下所示:

验证NULL值和普通值对IN和NOT IN的影响

从DEMO_WYDXBG A WHERE F1 IN(1,NULL) 中选择F1,F6;

执行结果显示,当列表中存在NULL时,IN可以正常查询结果。

从DEMO_WYDXBG 中选择F1,F6,其中F1 NOT IN(1,NULL);

执行结果显示,当列表中有NULL时,NOT IN无法查询到任何结果。

验证NULL值和普通值对EXISTS和NOT EXISTS的影响

SELECT F1,F6 FROM DEMO_WYDXBG A WHERE EXISTS(SELECT 1 FROM DEMO_WYDXBG B WHERE A.F1=B.F1 AND (A.F1=1 OR A.F1 IS NULL))

执行结果显示,当子查询数据包含NULL时,EXISTS可以正常查询结果,并且结果与IN查询的结果一致。

从DEMO_WYDXBG A 中选择F1,F6,其中不存在(从DEMO_WYDXBG B 中选择1,其中A.F1=B.F1 AND(A.F1=1 或A.F1 为NULL))

执行结果显示,当子查询数据包含NULL时,NOT EXISTS可以正常查询结果。

所以通过上面的例子我们可以得出以下结论:

IN、NOT IN 和EXISTS、NOT EXISTS 条件的含义不同。 IN 和EXISTS 在数据处理上没有区别。处理NULL 值时NOT IN 和NOT EXISTS 有不同的结果。那么为什么当NULL存在时NOT IN就不能查询结果呢?但NOT EXISTS可以吗?

不在的情况下

F1 NOT IN(1,NULL) 相当于F1!=1 AND F1 !=NULL 因为NULL 和任何表达式计算的结果都是未知的,所以当条件包含NULL 值时,条件一定不为真。所以当F1!=1 条件成立,但由于F1 !=NULL 条件不成立,因此无法获得结果。

那么为什么NOT EXISTS 不行呢?我们得从EXISTS的含义来解释。 EXISTS用于判断是否有数据。如果有数据,则为TRUE,如果没有,则为FALSE。 NOT EXISTS 恰恰相反。因此,当子查询中的NULL与DEMO_WYDXBG表上的任何数据匹配时,结果无效。因此,它们不能匹配。这意味着没有数据。没有数据就代表TRUE,所以可以查询数据。

IN和EXISTS的效率验证

我们已经验证了IN 和EXISTS 以及NOT IN 和NOT EXISTS 之间的区别。接下来我们要验证一下两者的效率。为此,我们需要创建两个新表,一张名为BIG_TABLE,一张名为SMALL_TABLE。

BIG_TABLE表结构如下:

BIG_TABLE总共有2000万条数据。使用循环随机插入数据。大约有100 万个唯一值。生成数据后,需要进行统计

调用dbms_stats.gather_table_stats(‘WYDXBG’,’BIG_TABLE’);

EXISTS 真的比IN 快吗?

SMALL_TABLE表结构如下:

SMALL_TABLE总共有20万条数据。循环插入数据,唯一值为100,000。生成数据后,需要进行统计

调用dbms_stats.gather_table_stats(‘WYDXBG’,’SMALL_TABLE’);

首先我们使用BIG_TABLE作为主表,SMALL_TABLE作为子查询中的表,并使用IN的写法。 SQL语句如下:

SELECT * FROM BIG_TABLE T WHERE T.F2 IN(SELECT T1.F2 FROM SMALL_TABLE T1 WHERE T1.F2 :A AND T1.F2=:B)

执行计划如下图所示:

之后我们使用BIG_TABLE作为主表,SMALL_TABLE作为子查询中的表,并使用EXISTS的写法。 SQL语句如下:

SELECT * FROM BIG_TABLE T WHERE EXISTS(SELECT F2 FROM SMALL_TABLE T1 WHERE T.F2=T1.F2 AND T1.F2 :A AND T1.F2=:B)

执行计划如下图所示:

什么?两者的执行计划居然是一样的?这与网上所说的不符。当然,我们不能据此得出两者的执行计划一定相同的结论。因为我们前面看到的执行计划称为预期执行计划,即SQL可能会这样执行,但实际上可能不会这样执行。

为了得到实际的执行计划,我们需要执行SQL。分别代入变量A和B的实际值。本例中A使用100,B使用2000,为了方便查找,在SQL中添加注释/*XYDXBG2021*/,然后执行该SQL。然后可以通过以下SQL语句查询SQL的运行状态select T.PLAN_HASH_VALUE,T.SQL_ID,T.SQL_TEXT from v$sql t where upper(t.sql_text) like ‘%XYDXBG2021%’

这里我们可以看到两条SQL文本不一致,但是它们的PLAN_HASH_VALUE是一致的,这说明两者使用的是同一个执行计划。这意味着使用IN 和EXISTS 在效率上是一致的。

然后我们找到它的详细执行计划来看看。您可以将SQL_ID替换为以下语句来查找真正的执行计划。

从表中选择*(dbms_xplan.display_cursor(‘bh6xzy3wq59u9’));

IN执行计划如下:

EXISTS执行计划如下:

两者确实完全相同,所以我们可以得出结论

当使用BIG_TABLE作为主表,使用SMALL_TABLE作为子查询中的表时,无论使用IN还是EXISTS,两者的效率是相同的。

我们看一下如果使用SMALL_TABLEL作为主表,使用BIG_TABLE作为子查询中的表,两者是否一致?采用IN写法,SQL语句如下:

SELECT * FROM SMALL_TABLE T WHERE T.F2 IN(SELECT T1.F2 FROM BIG_TABLE T1 WHERE T1.F2 :A AND T1.F2=:B)

IN执行计划如下:

EXISTS 真的比IN 快吗?

采用EXISTS写法,SQL语句如下:

SELECT * FROM SMALL_TABLE T WHERE EXISTS(SELECT F2 FROM BIG_TABLE T1 WHERE T.F2=T1.F2 AND T1.F2 :A AND T1.F2=:B)

EXISTS执行计划如下所示:

两人的预期执行计划是一致的。接下来,将变量A 和B 替换为实际值。本例中A使用100,B使用2000,为了方便查找,在SQL中添加注释/*XYDXBG2021*/,然后执行该SQL。

两条SQL的PLAN_HASH_VALUE一致,说明使用了相同的执行计划。

EXISTS的执行计划如下:

IN的执行计划如下:

两者完全相同,因此我们可以得出结论

当SMALL_TABLE作为主表,BIG_TABLE作为子查询中的表时,无论使用IN还是EXISTS,两者的效率是相同的。

除了上面两个DEMO之外,你还可以验证两个表都使用BIG_TABLE,并且都使用SMALL_TABLE示例,以及NOT EXISTS和NOT IN。你会发现他们的执行计划是一样的。

IN和EXISTS的结论

通过上面的验证,我们看到IN和EXISTS的执行计划是相同的,也就是说两者的性能是一致的。网上说EXISTS比IN快是不正确的。 NOT EXISTS 也不比NOT IN 快。但NOT EXISTS和NOT IN确实可能有不同的结果。所以使用NOT IN时需要特别注意NULL值。

为什么IN和EXISTS的执行计划是一致的?造成这个问题的原因在于Oracle的优化器模式。在基于成本的优化器中,Oracle会评估多个访问路径并最终选择成本最低的执行计划。因此,虽然SQL文本不一致,但是IN和EXISTS访问路径很可能是相同的。同时,Oracle会始终执行查询转换。 IN和EXISTS可以进行查询转换,转换后两者可能是等价的。因此,在基于成本的模型中,EXISTS 并不比IN 更有效。

当然,对于早期的优化器或基于规则的优化器,IN 和EXISTS 的性能可能不一致。此时,网络上广泛流传的计划也可能是正确的。但现在基于规则的优化器已经很少使用了,基本上都使用基于成本的优化器。

IN和EXISTS如何选择

那么如何在IN和EXISTS、NOT IN和NOT EXISTS之间进行选择呢?

对于NOT IN,由于返回NULL 值可能导致结果与预期不一致,请酌情考虑使用NOT EXISTS 代替NOT IN。

如果你的SQL比较简单,其实用IN还是EXISTS都没关系。两者的执行计划极有可能是相同的。但如果你只想查询几行数据,并且对相关条件有高效的索引,那么EXISTS 是一个不错的选择。因为这可能会导致优化器产生嵌套循环的执行计划。

如果你的SQL非常复杂,EXISTS中有多层嵌套,或者EXISTS中有多个表关联,那么建议你在这种情况下使用IN。主要原因是为了方便优化。

用户评论

EXISTS 真的比IN 快吗?
北染陌人

我觉得这完全取决于你的具体情况!如果数据量很大,使用 EXISTS 更加高效。因为它只需要检查是否存在一条符合条件的结果,而 IN 会对每个元素进行比较。

    有19位网友表示赞同!

EXISTS 真的比IN 快吗?
回到你身边

我做过几次测试,结果显示EXISTS确实比IN更快!当然,也要考虑其他因素,比如数据库引擎和查询复杂度。

    有19位网友表示赞同!

EXISTS 真的比IN 快吗?
烟花巷陌

这篇文章内容不错,解释得很清楚!我也经常遇到这种情况,所以以后我会优先使用EXISTS 作为比较工具。

    有8位网友表示赞同!

EXISTS 真的比IN 快吗?
凝残月

我可没那么快就能分辨出来EXISTS 和IN 哪种更快。测试结果有时候差异不大,还有很多其他优化方案可以考虑。

    有11位网友表示赞同!

EXISTS 真的比IN 快吗?
雁過藍天

别急着全面替换 IN 使用 EXISTS 吧!还是要看实际情况和数据量大小来决定最佳方案,而且某些情况下 IN 更简洁易读。

    有12位网友表示赞同!

EXISTS 真的比IN 快吗?
虚伪了的真心

如果数据量不大的话,两者的性能区别真的不太明显啊。不如优先考虑代码的可读性,用 IN 显得更容易理解。

    有20位网友表示赞同!

EXISTS 真的比IN 快吗?
水波映月

我一直以为 EXISTS 比 IN 快,看来我的认知并没有错误!感谢作者分享这篇文章,让我了解到更多的数据库优化技巧。

    有13位网友表示赞同!

EXISTS 真的比IN 快吗?
此刻不是了i

数据量很大时EXISTS确实更快,但这只适用于存在条件的精确查询。当查询涉及模糊匹配或者比较等运算时,IN 可能更加高效

    有10位网友表示赞同!

EXISTS 真的比IN 快吗?
余温散尽ぺ

我更喜欢简洁明了的代码风格,所以一般会选择 IN 使用。即使 EXISTS 速度更快,可读性和维护性也很重要。

    有11位网友表示赞同!

EXISTS 真的比IN 快吗?
颓废i

这篇文章说的很有道理!以后遇到这种查询情况,我会先试用EXISTS 看性能表现,如果有差距,再根据具体需求选择合适的方法。

    有12位网友表示赞同!

EXISTS 真的比IN 快吗?
哭着哭着就萌了°

测试结果很重要,但不能忽略实际运用场景的差异。不同的数据库引擎和硬件配置也会对 EXISTS 和 IN 的性能产生影响

    有7位网友表示赞同!

EXISTS 真的比IN 快吗?
心亡则人忘

我发现Sometimes exist s is used where an IN clause would be faster. it's good to keep both in mind and test, depending on the use case.

    有16位网友表示赞同!

EXISTS 真的比IN 快吗?
滴在键盘上的泪

这篇文章让我对EXISTS 和IN 使用有了更深入的理解!以前一直认为他们差不多,现在我才知道有这么大的区别.

    有15位网友表示赞同!

EXISTS 真的比IN 快吗?
盲从于你

其实EXISTS 不仅比 IN 快,在某些情况下它还可以节省资源。因为 EXISTS 只需要检查数据是否存在,而 IN 会遍历所有匹配项。

    有12位网友表示赞同!

EXISTS 真的比IN 快吗?
挽手余生ら

虽然 Exists can be faster than IN in some cases, but it's important to consider the complexity of your query and the size of your dataset.

    有15位网友表示赞同!

EXISTS 真的比IN 快吗?
凉凉凉”凉但是人心

文章的测试用例很有价值!但希望作者可以加入更多实际应用场景的分析,这样更有帮助。

    有6位网友表示赞同!

EXISTS 真的比IN 快吗?
罪歌

EXISTS 和 IN 的性能差别并不總是明顯。 很多时候其他因素,比如索引优化,对查询速度影响更大

    有12位网友表示赞同!

原创文章,作者:小su,如若转载,请注明出处:https://www.sudun.com/ask/120548.html

(0)
小su's avatar小su
上一篇 2024年9月1日 下午1:13
下一篇 2024年9月1日 下午1:16

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注