Oracle的IN vs OR,哪个更快?

Posted

技术标签:

【中文标题】Oracle的IN vs OR,哪个更快?【英文标题】:IN vs OR of Oracle, which faster? 【发布时间】:2011-09-24 18:53:48 【问题描述】:

我正在开发一个应用程序来处理 Oracle 数据库中的许多数据。 在某些情况下,我必须根据给定的条件列表获取许多对象,我使用SELECT ...FROM.. WHERE... IN...,但IN 表达式只接受一个最大为 1,000 个项目的列表。

所以我改用OR 表达式,但正如我观察到的——也许这个查询(使用OR)比IN 慢(使用相同的条件列表)。这样对吗?如果是这样,如何提高查询速度?

【问题讨论】:

列表是静态的还是来自查询? 否,要查询的值列表是从外部资源中检索的。有什么办法可以解决这个问题,因为我的列表太大,可能包含超过 100000 个项目 那么,您正在创建一个包含类似 IN (...9997, 9998, 9999, 1000,1001 ...) 的大型查询字符串?传输和解析这本身就会花费很多。没关系 sql 注入的可能性。 【参考方案1】:

INOR 更可取——OR 是出了名的糟糕表现,并且可能导致需要在复杂查询中使用括号的其他问题。

INOR 更好的选择是加入包含您想要(或不想要)的值的表。此用于比较的表可以是派生的、临时的或已存在于您的架构中。

【讨论】:

不,我只查询一张表。我的列表可能包含太多项目,因此我不能使用 IN。我尝试将列表拆分成更小的部分,对一批子列表进行查询,但后来我必须在内存中排序数据,这很慢。 IN 和 OR 不一样吗?也就是说,无论如何 IN 扩展到 OR ?这就是 NOT IN with NULL 失败的原因 @gbn:从逻辑上讲,是的。但是IN 比使用OR 进行了优化——它不仅仅是语法糖。 你能证明 IN 不仅仅是语法糖吗?我在答案中测试并发布了结果。 @jva:一般政策是有人回应后投反对票,而不是之前投反对票。坦率地说,这是试图宣传您的答案。请记住,答案会老化 - 较新的版本可能意味着无法保证行为。【参考方案2】:

在这种情况下,我会这样做:

    创建单列全局临时表 使用您从外部来源获得的列表填充此表(并且快速 - 另一个完整的讨论) 通过将临时表连接到另一个表来执行查询(考虑动态抽样,因为临时表不会有很好的统计信息)

这意味着您可以将排序留给数据库并编写一个简单的查询。

【讨论】:

【参考方案3】:

无论如何,Oracle 在内部将 IN 列表转换为 OR 列表,因此实际上应该没有性能差异。唯一的区别是 Oracle 必须转换 IN,但如果您自己提供 OR,则需要解析更长的字符串。

这是你如何测试它。

CREATE TABLE my_test (id NUMBER);

SELECT 1 
FROM my_test
WHERE id IN (1,2,3,4,5,6,7,8,9,10,
             21,22,23,24,25,26,27,28,29,30,
             31,32,33,34,35,36,37,38,39,40,
             41,42,43,44,45,46,47,48,49,50,
             51,52,53,54,55,56,57,58,59,60,
             61,62,63,64,65,66,67,68,69,70,
             71,72,73,74,75,76,77,78,79,80,
             81,82,83,84,85,86,87,88,89,90,
             91,92,93,94,95,96,97,98,99,100
             );

SELECT sql_text, hash_value
FROM v$sql 
WHERE sql_text LIKE '%my_test%';

SELECT operation, options, filter_predicates
FROM v$sql_plan
WHERE hash_value = '1181594990'; -- hash_value from previous query

选择声明 表访问已满(“ID”=1 或“ID”=2 或“ID”=3 或“ID”=4 或“ID”=5 或 "ID"=6 或 "ID"=7 或 "ID"=8 或 "ID"=9 或 "ID"=10 或 "ID"=21 或 "ID"=22 或 "ID"=23 或 "ID"=24 或 "ID"=25 或 "ID"=26 或 "ID"=27 或 "ID"=28 或 "ID"=29 或 "ID"=30 或 "ID"=31 或 "ID"=32 或 "ID"=33 或 "ID"=34 或 "ID"=35 或 "ID"=36 或 "ID"=37 或 "ID"=38 或 "ID"=39 或 "ID"=40 或 "ID"=41 或 "ID"=42 或 "ID"=43 或 "ID"=44 或 "ID"=45 或 "ID"=46 或 "ID"=47 或 "ID"=48 或 "ID"=49 或 "ID"=50 或 "ID"=51 或 "ID"=52 或 "ID"=53 或 "ID"=54 或 "ID"=55 或 "ID"=56 或 "ID"=57 或 "ID"=58 或 "ID"=59 或 "ID"=60 或 "ID"=61 或 "ID"=62 或 "ID"=63 或 "ID"=64 或 "ID"=65 或 "ID"=66 或 "ID"=67 或 "ID"=68 或 "ID"=69 或 "ID"=70 或 "ID"=71 或 "ID"=72 或 "ID"=73 或 "ID"=74 或 "ID"=75 或 "ID"=76 或 "ID"=77 或 "ID"=78 或 "ID"=79 或 "ID"=80 或 "ID"=81 或 "ID"=82 或 "ID"=83 或 "ID"=84 或 "ID"=85 或​​ "ID"=86 或 "ID"=87 或 "ID"=88 或 "ID"=89 或 "ID"=90 或 "ID"=91 或 "ID"=92 或 "ID"=93 或 "ID"=94 或 "ID"=95 或 "ID"=96 或 "ID"=97 或 "ID"=98 或 "ID"=99 或 "ID"=100)

【讨论】:

您创建的表是堆表 - 没有主键/索引 @OMGPonies Plus 1 关于您不反对 jva 作为报复的回答。我知道这里有很多人会这样做。【参考方案4】:

我会质疑整个方法。 SP 的客户端必须发送 100000 个 ID。客户从哪里获得这些 ID?发送如此大量的 ID 作为 proc 的参数无论如何都会花费很大的成本。

【讨论】:

【参考方案5】:

如果您使用主键创建表:

CREATE TABLE my_test (id NUMBER,
CONSTRAINT PK PRIMARY KEY (id));

并通过相同的 SELECT 运行具有多个 IN 值的查询,然后通过哈希值检索执行计划,您得到的是:

SELECT STATEMENT
INLIST ITERATOR
INDEX                  RANGE SCAN

这似乎暗示,当您有一个 IN 列表并将其与 PK 列一起使用时,Oracle 将在内部将该列表保留为“INLIST”,因为它更有效地处理它,而不是将其转换为 OR,如未索引表的情况。

我使用的是上面的 Oracle 10gR2。

【讨论】:

感谢测试。如果该列没有被索引怎么办?还会是多重OR吗?

以上是关于Oracle的IN vs OR,哪个更快?的主要内容,如果未能解决你的问题,请参考以下文章

NSDictionary VS NSArray+NSPredicate:哪个更快/推荐

CSS vs. JS Animation: 哪个更快

for vs foreach vs while 哪个在 php 中遍历数组更快

2dsphere vs 2d index:哪个“更好”/更快?

哪个Oracle查询更快

Dapper vs ADO.Net用反射哪个更快?