Oracle 查询中避免更新字段的最佳方法是什么(如果未更改)?

What is the best way in Oracle query, to avoid updating a field , if that is unchanged?

我只是想知道我可以在 Oracle 查询中使用的最佳方法,以避免更新字段(如果未更改)?

Update xtab1 set xfield1='xxx' where xkey='123';

在性能方面,如果 xfield1 的现有值为 'xxx',则不应调用此更新的最佳方法是什么。

选项 1:

  • step1:Invoke a SELECT to Fetch the value of xfield1
  • step2:If the above value is not 'xxx', then only invoke UPDATE

选项 2:

  • Invoke update as below:

    Update xtab1 set xfield1='xxx' where xkey='123' and xfield1 <> 'xxx'

请告诉我以上两种方法中哪一种是最佳和理想的方法,或者是否有其他理想的方法可以使用?

感谢您的帮助

我认为这两个选项之间不会有显着的性能差异,因为两者都需要查找行并对值进行比较。而且我怀疑其他选项(例如更新前触发器)会产生比您的选项 2 更好的性能。

如果您真的想知道 Oracle 优化器如何处理您的查询,请尝试 EXPLAIN PLAN statement。例如,要查看 Oracle 优化器制定的执行第二个选项的计划,请尝试以下操作:

EXPLAIN PLAN FOR
UPDATE xtab1 SET xfield1='xxx' 
WHERE xkey='123' AND xfield1 <> 'xxx'

在此 SO post.

中有更多关于 EXPLAIN PLAN 结果的不同列的含义的信息

现在,如果您要处理大量事务,我建议考虑其他选项,例如在应用程序级别比较值,从而尽可能避免昂贵的数据库 I/Os :-)或使用某种形式的经过优化以处理大型事务的 ETL 工具。

Update xtab1 set xfield1='xxx' where xkey='123' and xfield1 <> 'xxx'

过滤器谓词 在执行更新之前应用。因此,我会选择选项 2,让 Oracle 为您完成这项工作,而不是手动执行以首先过滤掉行。此外,在两个不同的步骤中执行此操作将是一项开销。行的过滤应该是同一步骤的一部分。

关于性能,我认为indexes会起到重要作用。

你可以测试看看:

无索引

选项 1

SQL> EXPLAIN PLAN FOR
  2  UPDATE t SET sal = 9999 WHERE deptno = 20;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 931696821

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |      |     5 |    35 |     3   (0)| 00:00:01 |
|   1 |  UPDATE            | T    |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| T    |     5 |    35 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("DEPTNO"=20)

14 rows selected.

SQL>

选项 2

SQL> EXPLAIN PLAN FOR
  2  UPDATE t SET sal = 9999 WHERE deptno = 20 AND sal<>9999;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 931696821

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |      |     4 |    28 |     3   (0)| 00:00:01 |
|   1 |  UPDATE            | T    |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| T    |     4 |    28 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("DEPTNO"=20 AND "SAL"<>9999)

14 rows selected.

有索引

SQL> CREATE INDEX t_idx ON t(deptno,sal);

Index created.

选项 1

SQL> EXPLAIN PLAN FOR
  2  UPDATE t SET sal = 9999 WHERE deptno = 20;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1175576152

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | UPDATE STATEMENT  |       |     5 |    35 |     1   (0)| 00:00:01 |
|   1 |  UPDATE           | T     |       |       |            |          |
|*  2 |   INDEX RANGE SCAN| T_IDX |     5 |    35 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------

   2 - access("DEPTNO"=20)

14 rows selected.

SQL>

选项 2

SQL> EXPLAIN PLAN FOR
  2  UPDATE t SET sal = 9999 WHERE deptno = 20 AND sal<>9999;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1175576152

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | UPDATE STATEMENT  |       |     4 |    28 |     1   (0)| 00:00:01 |
|   1 |  UPDATE           | T     |       |       |            |          |
|*  2 |   INDEX RANGE SCAN| T_IDX |     4 |    28 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------

   2 - access("DEPTNO"=20)
       filter("SAL"<>9999)

15 rows selected.

SQL>

因此,在所有情况下,在选项 2 中,应用 filter("SAL"<>9999)

你会在哪里获取值?在某些应用程序中?

我认为对于较小的查询,两者之间不会有太大区别。对于更复杂的问题,我建议选择第二个选项,让 Oracle 为您优化查询以获得最佳结果。

谢谢大家

我选择了选项 2,甚至我的 DBA 也同意这是更好的方法。