如何优化在具有700M行的Oracle表上运行的更新SQL
[TABLE]是一个Oracle数据库表,有超过7亿行。在SQL运行了6个小时后,我取消了它的执行 是否有任何SQL提示可以提高性能?或者有其他的解决方案来加速如何优化在具有700M行的Oracle表上运行的更新SQL,sql,performance,oracle,oracle10g,Sql,Performance,Oracle,Oracle10g,[TABLE]是一个Oracle数据库表,有超过7亿行。在SQL运行了6个小时后,我取消了它的执行 是否有任何SQL提示可以提高性能?或者有其他的解决方案来加速 编辑:此查询将运行一次,然后再也不会运行。通过使用ALTER table将列“DEFAULT”值设置为0,您可以在不进行更新的情况下获得相同的结果。首先,它是一次性查询还是重复查询?如果您只需要执行一次,那么您可能希望在并行模式下运行查询。无论如何,您都必须扫描所有行,您可以使用ROWID的范围来划分工作负载(自己动手并行),也可以使用
编辑:此查询将运行一次,然后再也不会运行。通过使用ALTER table将列“DEFAULT”值设置为0,您可以在不进行更新的情况下获得相同的结果。首先,它是一次性查询还是重复查询?如果您只需要执行一次,那么您可能希望在并行模式下运行查询。无论如何,您都必须扫描所有行,您可以使用ROWID的范围来划分工作负载(自己动手并行),也可以使用Oracle内置功能 假设您希望经常运行它并希望优化此查询,则
字段
列为NULL的行数最终将比总行数小。在这种情况下,索引可以加快速度。Oracle不会将所有索引列均为NULL的行编入索引,因此您的查询不会使用字段
上的索引(因为您希望查找字段
为NULL的所有行)
要么:
- 在
上创建索引,(字段,0)
将充当非空伪列,并且表上的所有行都将被索引0
- 在
,这将只索引为NULL的行(因此索引将非常紧凑)。在这种情况下,您必须重写查询:上创建基于函数的索引(如果字段为NULL,则为1 END)
UPDATE[TABLE]SET[FIELD]=0,其中(字段为空时为1 END)=1
PARALLEL
提示:
UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL
文森特已经完美地回答了你的问题,但我很好奇这次行动背后的“原因”。为什么要将所有NULL更新为0 问候,, Rob.一些建议:
希望这有帮助。其他用户是否同时更新表中的相同行 如果是这样,您可能会遇到很多并发性问题(等待锁),将其分解为较小的事务可能是值得的
SQL> EXPLAIN PLAN FOR
2 UPDATE /*+ PARALLEL(test_table 4)*/ test_table
3 SET field=0
4 WHERE field IS NULL;
Explained
SQL> select * from table( dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4026746538
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 22793 | 289K| 12 (9)| 00:00:
| 1 | UPDATE | TEST_TABLE | | | |
| 2 | PX COORDINATOR | | | | |
| 3 | PX SEND QC (RANDOM)| :TQ10000 | 22793 | 289K| 12 (9)| 00:00:
| 4 | PX BLOCK ITERATOR | | 22793 | 289K| 12 (9)| 00:00:
|* 5 | TABLE ACCESS FULL| TEST_TABLE | 22793 | 289K| 12 (9)| 00:00:
--------------------------------------------------------------------------------
声明
v_cnt编号:=1;
开始
当v_cnt>0循环时
更新[表格]设置[字段]=0,其中[字段]为空且ROWNUM<50000;
v_cnt:=SQL%ROWCOUNT;
犯罪
端环;
结束;
/
ROWNUM限制越小,并发/锁定问题就越少,但扫描表的时间就越多。您好,这是一个一次性查询。但是,感谢您在回答中涵盖了这两种情况(一次性查询/重复查询)。很好地使用了解释计划示例,这会更快吗?它会更快,因为它不会以任何方式更新表数据,只更新表定义OK,但在这种情况下,我必须更新现有的行,而不仅仅是表定义。不,您是在告诉Oracle在遇到NULL时传递默认值零而不是NULL值——所有这些都发生在选择处理上,实际表没有更新。-1抱歉,这不起作用。更改默认值不会更新现有行。(在Oracle 11g中,只有在一次操作中添加了一个新列,该列同时具有默认值和NOTNULL约束,这种“廉价更新”技巧才有效。)问得好,Rob。这是因为在普通索引中不跟踪空值。在这种情况下,执行更新和更改数据的语义似乎相当激烈。您可以创建一个基于函数的索引,或者在([field],1)上创建一个常规索引。是的,这是我们一直在考虑的一种方法。感谢您确保在更新后添加NOTNULL约束,这样您就不必再这样做了。
DECLARE
v_cnt number := 1;
BEGIN
WHILE v_cnt > 0 LOOP
UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL AND ROWNUM < 50000;
v_cnt := SQL%ROWCOUNT;
COMMIT;
END LOOP;
END;
/