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

发布于 2024-10-16 16:50:34 字数 191 浏览 4 评论 0原文

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

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

如果是这样,可以采取什么措施来加快执行速度?

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

In the above query, imagine the inner query returns 10000 rows. Does this query with IN clause affect performance?

If so, what can be done for faster execution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我最亲爱的 2024-10-23 16:50:34

如果子查询返回的行数与 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 中读取行,并对每个(唯一)行执行索引访问表 1。

哪种访问速度更快取决于内部查询的选择性和 TABLE1 上索引的聚类(TABLE1 中 col2 值相似的行是相邻的还是随机分布的?)。无论如何,从性能角度来看,如果您需要执行此更新,此查询是最快的方法之一。

if the subquery returns a large number of rows compared to the number of rows in TABLE1, the optimizer will likely produce a plan like this:

--------------------------------------------------------------------------------
| 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")

It will scan both tables once and update only the rows in TABLE1 common to both tables. This is a highly efficient plan if you need to update lots of rows.

Sometimes the inner query will have few rows compared to the number of rows in TABLE1. If you have an index on TABLE1(col2), you could then obtain a plan similar to this one:

-------------------------------------------------------------------------------
| 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")

In that case Oracle will read the rows from TABLE2 and for each (unique) row, perform an index access on TABLE1.

Which access is faster depend upon the selectivity of the inner query and the clustering of the index on TABLE1 (are the rows with similar value of col2 in TABLE1 next to each other or randomly spread?). In any case, performance wise, if you need to perform this update this query is one of the fastest way to do it.

街角迷惘 2024-10-23 16:50:34
UPDATE table1 outer
   SET col1 = 'Y'
 WHERE EXISTS (select null
                 from table2
                WHERE col2 = outer.col2)

这可能会更好

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

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

This could be better

To get the idea which is better - look at the execution plan.

冷月断魂刀 2024-10-23 16:50:34

来自甲骨文:

11.5.3.4 在子查询中使用 EXISTS 与 IN

在某些情况下,这是更好的
使用 IN 而不是 EXISTS。在
一般情况下,如果选择性谓词是
在子查询中,然后使用IN。如果
选择性谓词位于父级中
查询,然后使用 EXISTS。

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

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

From Oracle:

11.5.3.4 Use of EXISTS versus IN for Subqueries

In certain circumstances, it is better
to use IN rather than EXISTS. In
general, if the selective predicate is
in the subquery, then use IN. If the
selective predicate is in the parent
query, then use EXISTS.

From my experience, I have seen better plans using EXISTS where subquery returns large amount of rows.

See here for more discussion from Oracle

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文