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 也同意这是更好的方法。
我只是想知道我可以在 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 也同意这是更好的方法。