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查询中最好的方法是啥,以避免更新字段,如果它没有改变?的主要内容,如果未能解决你的问题,请参考以下文章