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

b.r*_*oth 10 sql oracle performance oracle10g

UPDATE [TABLE] SET [FIELD]=0 WHERE [FIELD] IS NULL
Run Code Online (Sandbox Code Playgroud)

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

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

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

Vin*_*rat 11

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

假设您想要经常运行它并希望优化此查询,那么field列总数为NULL 的行数最终将与总行数相比较小.在这种情况下,索引可以加快速度.Oracle不会将所有索引列的行编入为NULL,因此field查询不会使用索引(因为您要查找所有fieldNULL为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:
--------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)


Gar*_*ers 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;
/
Run Code Online (Sandbox Code Playgroud)

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