Oracle查询中最好的方法是啥,以避免更新字段,如果它没有改变?

Posted

技术标签:

【中文标题】Oracle查询中最好的方法是啥,以避免更新字段,如果它没有改变?【英文标题】:What is the best way in Oracle query, to avoid updating a field , if that is unchanged?Oracle查询中最好的方法是什么,以避免更新字段,如果它没有改变? 【发布时间】:2015-04-14 05:30:08 【问题描述】:

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

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

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

选项1:

step1:调用 SELECT 来获取 xfield1 的值 step2:如果上面的值不是'xxx',那么只调用UPDATE

选项2:

调用更新如下:

更新 xtab1 设置 xfield1='xxx' where xkey='123' and xfield1 'xxx'

请让我知道以上两种方法中哪一种是最好和理想的方法,或者还有其他理想的方法可以使用吗?

感谢您的帮助

【问题讨论】:

【参考方案1】:

更新 xtab1 设置 xfield1='xxx' where xkey='123' and xfield1 'xxx'

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

关于性能,我认为索引会发挥重要作用。

你可以测试一下看看:

无索引

选项 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)

【讨论】:

【参考方案2】:

我认为这两个选项之间不会有显着的性能差异,因为两者都需要查找行并执行值比较。而且我怀疑其他选项(例如更新前触发器)会比您的选项 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/O :-) 或使用某种形式为处理大型事务而优化的 ETL 工具。

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

谢谢大家。

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

【讨论】:

以上是关于Oracle查询中最好的方法是啥,以避免更新字段,如果它没有改变?的主要内容,如果未能解决你的问题,请参考以下文章

从 Oracle 函数返回记录的标准方法是啥?

使用 JPA 获取集合时避免 N+1 和笛卡尔积问题的标准方法是啥

Oracle全文检索是啥意思?

oracle查询重复数据方法

Oracle中nvl函数的用法和作用是啥?

sql语句中字符串的连接符是啥?