IN子句如何影响oracle中的性能?

Viv*_*vek 7 sql oracle performance

UPDATE table1 
       SET col1 = 'Y'
     WHERE col2 in (select col2 from table2)
Run Code Online (Sandbox Code Playgroud)

在上面的查询中,假设内部查询返回10000行.带有IN子句的查询是否会影响性能?

如果是这样,可以做些什么来加快执行速度?

Vin*_*rat 11

如果子查询与TABLE1中的行数相比返回大量行,则优化器可能会生成如下计划:

--------------------------------------------------------------------------------
| Id  | Operation           | Name   | Rows  | Bytes |TempSpc| Cost (%CPU)| Time
--------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT    |        |   300K|    24M|       |  1581   (1)| 00:0
|   1 |  UPDATE             | TABLE1 |       |       |       |            |
|*  2 |   HASH JOIN SEMI    |        |   300K|    24M|  9384K|  1581   (1)| 00:0
|   3 |    TABLE ACCESS FULL| TABLE1 |   300K|  5860K|       |   355   (2)| 00:0
|   4 |    TABLE ACCESS FULL| TABLE2 |   168K|    10M|       |   144   (2)| 00:0
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("COL2"="COL2")
Run Code Online (Sandbox Code Playgroud)

它将扫描两个表并仅更新两个表共有的TABLE1中的行.如果您需要更新大量行,这是一个高效的计划.

有时,与TABLE1中的行数相比,内部查询将具有很少的行.如果您有索引TABLE1(col2),则可以获得类似于此的计划:

-------------------------------------------------------------------------------
| Id  | Operation            | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT     |        |    93 |  4557 |   247   (1)| 00:00:03 |
|   1 |  UPDATE              | TABLE1 |       |       |            |          |
|   2 |   NESTED LOOPS       |        |    93 |  4557 |   247   (1)| 00:00:03 |
|   3 |    SORT UNIQUE       |        |    51 |  1326 |   142   (0)| 00:00:02 |
|   4 |     TABLE ACCESS FULL| TABLE2 |    51 |  1326 |   142   (0)| 00:00:02 |
|*  5 |    INDEX RANGE SCAN  | IDX1   |     2 |    46 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("T1"."COL2"="T2"."COL2")
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Oracle将读取TABLE2中的行,并为每个(唯一)行执行对TABLE1的索引访问.

哪个访问更快取决于内部查询的选择性和TABLE1上索引的聚类(TABLE1中具有相似值的行col2是彼此相邻还是随机扩展?).在任何情况下,性能方面,如果您需要执行此更新,此查询是最快的方法之一.

  • @zerkms:抱歉,我忘了提到优化器将IN子查询转换为等效的EXIST子查询.因此,他们制定了相同的计划.我个人发现IN语句更具可读性,但这是非常主观的:) (3认同)

zer*_*kms 3

UPDATE table1 outer
   SET col1 = 'Y'
 WHERE EXISTS (select null
                 from table2
                WHERE col2 = outer.col2)
Run Code Online (Sandbox Code Playgroud)

这可能会更好

要了解哪个更好,请查看执行计划。

  • 我认为这是一个已解决的问题,因为对于 Oracle 优化器来说,IN 和 EXISTS 之间通常没有区别,并且一个会根据需要转换为另一个。http://blogs.oracle.com/optimizer/2010/09/optimizer_transformations_subquery_unesting_part_1.html (2认同)