优化具有数百万条记录的表上的删除操作

时间:2014-10-09 09:46:43

标签: sql oracle

我有一个包含多列的表格。 "理由"是非索引列之一,可能具有重复值。在我的表中总共有二十万条记录。我想根据特定原因删除行,例如" MY REASON",而有大约15K记录" MY REASON"。

当我使用如下所示的标准删除查询时,需要花费太多时间(大约3或4个小时)。

delete from my_table where reason='MY REASON';
commit;

如何加快速度?

这是相同的执行计划:

   Plan hash value: 2164670663
   | Id  | Operation          | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
   ---------------------------------------------------------------------------------------
   |   0 | DELETE STATEMENT   |                  |  6190 |   175K|  1019   (0)| 10:30:49 |
   |   1 |  DELETE            | MY_TABLE         |       |       |            |          |
   |*  2 |   TABLE ACCESS FULL| MY_TABLE         |  6190 |   175K|  1019   (0)| 10:30:49 |
   ---------------------------------------------------------------------------------------

   Predicate Information (identified by operation id):
   ---------------------------------------------------

   2 - filter("REASON"='MY REASON')

使用主键删除10row的统计信息,id:

SQL> set timing on;
SQL> set autotrace on explain statistics;
SQL> delete from my_table where id between 194404 and 194414;

11 rows deleted.

Elapsed: 00:00:19.53

Execution Plan
----------------------------------------------------------
Plan hash value: 2403087528

---------------------------------------------------------------------------------------

| Id  | Operation         | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------

|   0 | DELETE STATEMENT  |                   |     1 |    29 |     1   (0)| 00:00:38 |

|   1 |  DELETE           | MY_TABLE          |       |       |            |      |

|*  2 |   INDEX RANGE SCAN| PK_MY_TABLE       |     1 |    29 |     1   (0)| 00:00:38 |

---------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("id">=194404 AND "id"<=194414)


Statistics
----------------------------------------------------------
         94  recursive calls
         66  db block gets
     602170  consistent gets
          0  physical reads
       8844  redo size
        528  bytes sent via SQL*Net to client
        372  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          7  sorts (memory)
          0  sorts (disk)
         11  rows processed

SQL>

*在儿童桌上添加指数后固定的问题*** 以下是跟踪详细信息:

AFTER ADDING INDEX TO CHILD TABLE
---------------------------------
SQL> set timing on;
SQL> set autotrace on explain statistics;
SQL> delete from MY_TABLE where id between 194241 and 194361;

121 rows deleted.

Elapsed: 00:00:01.37

Execution Plan
----------------------------------------------------------
Plan hash value: 2403087528

---------------------------------------------------------------------------------------

| Id  | Operation         | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------

|   0 | DELETE STATEMENT  |                   |     1 |    29 |     1   (0)| 00:00:38 |

|   1 |  DELETE           | MY_TABLE          |       |       |            |      |

|*  2 |   INDEX RANGE SCAN| PK_MY_TABLE       |     1 |    29 |     1   (0)| 00:00:38 |

---------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID">=194241 AND "ID"<=194361)


Statistics
----------------------------------------------------------
          3  recursive calls
        760  db block gets
          7  consistent gets
          9  physical reads
      83968  redo size
        527  bytes sent via SQL*Net to client
        372  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          5  sorts (memory)
          0  sorts (disk)
        121  rows processed

2 个答案:

答案 0 :(得分:2)

检查外键约束中列的索引。不仅在您的my_table中,而且在您的所有数据库中。每个外键应在同一列列上具有相应的索引。

创建缺失的索引(具有明确的临时名称,因此您可以在以后轻松删除它们)。

然后再次尝试运行delete

答案 1 :(得分:1)

如果删除需要花费很多时间,你可以尝试这样的事情:

1)

CREATE TABLE BACK_MY_TABLE AS SELECT * FROM MY_TABLE 
  where reason not in ('MY REASON');  

2)DROP TABLE MY_TABLE
3)ALTER TABLE BACK_MY_TABLE RENAME TO MY_TABLE

在我看来,有很多索引在路上重建/你在某处使用位图索引。

此外,由于这是Oracle,因此您可以设置允许某些用户(例如,可能是运行这些删除作业的清理用户)的使用者组仅获得X%的可用资源。通过 DEFAULT ,每个进程都会尝试获取所有资源的100%。这会导致争用,并可能极大地影响您的表现。