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

时间:2011-02-10 13:55:47

标签: sql performance oracle

UPDATE table1 
       SET col1 = 'Y'
     WHERE col2 in (select col2 from table2)

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

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

3 个答案:

答案 0 :(得分: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")

它将扫描两个表并仅更新两个表共有的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")

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

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

答案 1 :(得分:3)

UPDATE table1 outer
   SET col1 = 'Y'
 WHERE EXISTS (select null
                 from table2
                WHERE col2 = outer.col2)

这可能会更好

要获得更好的想法 - 请查看执行计划。

答案 2 :(得分:2)

来自Oracle:

  

11.5.3.4使用EXISTS与IN进行子查询

     

在某些情况下,它会更好   使用IN而不是EXISTS。在   一般来说,如果选择性谓词是   在子查询中,然后使用IN。如果   选择性谓词在父母中   查询,然后使用EXISTS。

根据我的经验,我已经看到使用EXISTS的更好计划,其中子查询返回大量行。

有关Oracle的更多讨论,请参阅here