如何优化在具有700M行的Oracle表上运行的更新SQL

时间:2010-06-03 08:48:35

标签: sql performance oracle oracle10g

UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL

[TABLE]是一个超过7亿行的Oracle数据库表。我在运行6小时后取消了SQL执行。

是否有任何SQL提示可以提高性能?或任何其他解决方案来加快速度?

编辑:此查询将运行一次,然后再不会运行。

5 个答案:

答案 0 :(得分:10)

首先是一次性查询还是循环查询?如果您只想在并行模式下查看运行查询,则必须执行此操作。您无论如何都必须扫描所有行,您可以使用ROWID(自己动手并行)范围自行划分工作负载,也可以使用Oracle内置功能。<​​/ p>

假设您想要经常运行它并想要优化此查询,那么field列为NULL的行数最终会比总行数小。在这种情况下,索引可以加快速度。 Oracle不会将所有索引列的行编入为NULL,因此查询不会使用field上的索引(因为您要查找field为NULL的所有行)。

或者:

  • (FIELD, 0)上创建索引,0将充当非NULL伪列,并且所有行都将在表格上编入索引。
  • (CASE WHEN field IS NULL THEN 1 END)上创建一个基于函数的索引,这只会索引为NULL的行(索引因此非常紧凑)。在这种情况下,您将不得不重写您的查询:

    UPDATE [TABLE] SET [FIELD]=0 WHERE (CASE WHEN field IS NULL THEN 1 END)=1

编辑:

由于这是一次性方案,您可能需要使用PARALLEL提示:

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:
--------------------------------------------------------------------------------

答案 1 :(得分:5)

其他用户是否同时更新表中的相同行?

如果是这样,您可能会遇到很多并发问题(等待锁定),并且可能值得将其分解为较小的事务。

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;
/

ROWNUM限制越小,您遇到的并发/锁定问题就越少,但您在表扫描中花费的时间就越多。

答案 2 :(得分:3)

文森特已经完全回答了你的问题,但我很好奇这一行动背后的“原因”。为什么要将所有NULL更新为0?

此致 罗布。

答案 3 :(得分:1)

一些建议:

  1. 在运行UPDATE语句之前删除包含FIELD的所有索引,然后再重新添加它们。

  2. 编写一个PL / SQL过程来执行此操作,该过程在每1000或10000行之后提交。

  3. 希望这有帮助。

答案 4 :(得分:0)

通过使用ALTER表将列“DEFAULT”值设置为0,您可以在不进行更新的情况下获得相同的结果。