Sql 为什么删除时间比插入时间长

Sql 为什么删除时间比插入时间长,sql,oracle,performance,Sql,Oracle,Performance,为什么执行delete语句要比insert语句花费更长的时间 据我所知,delete会触发索引和重做更改以及数据块。删除也是如此 因此,我认为两条语句在同一个表上的执行时间相似。但完全不同。这有什么区别 作为参考,dbms供应商是Oracle。该表没有触发器,并且绑定了两个索引 这只是一个简单的删除删除,其中cDe> 201411 < p>无论如何,如果要删除所有行,如果可能,请考虑使用截断。 如果删除使用WHERE子句考虑您正在为索引进行索引查找(但请记住,为删除而更新索引也会导致一些开销

为什么执行delete语句要比insert语句花费更长的时间

据我所知,delete会触发索引和重做更改以及数据块。删除也是如此

因此,我认为两条语句在同一个表上的执行时间相似。但完全不同。这有什么区别

作为参考,dbms供应商是Oracle。该表没有触发器,并且绑定了两个索引


这只是一个简单的删除删除,<代码>其中cDe> 201411

< p>无论如何,如果要删除所有行,如果可能,请考虑使用截断。

如果删除使用WHERE子句考虑您正在为索引进行索引查找(但请记住,为删除而更新索引也会导致一些开销)

可能存在当前正在使用当前对象的会话(行可能会相对于删除记录锁定)。它正在等待,直到会话被清除或关闭

回滚段也会花费您的时间

此外,有关优化大规模删除的信息,请参阅:

一,


2.

如果我正确理解了问题,您想知道为什么一般情况下删除插入花费的时间更长

让我们以一个具有自动跟踪统计信息的实际例子来解释原因

插入自动跟踪统计信息

SQL> SET AUTOTRACE ON
SQL> INSERT INTO t(A) SELECT LEVEL FROM dual CONNECT BY LEVEL <=1000;

1000 rows created.


Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

------------------------------------------------------------------------------
| Id  | Operation                     | Name | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | INSERT STATEMENT              |      |     1 |     2   (0)| 00:00:01 |
|   1 |  LOAD TABLE CONVENTIONAL      | T    |       |            |          |
|*  2 |   CONNECT BY WITHOUT FILTERING|      |       |            |          |
|   3 |    FAST DUAL                  |      |     1 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

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

   2 - filter(LEVEL<=1000)


Statistics
----------------------------------------------------------
         43  recursive calls
         63  db block gets
         32  consistent gets
          0  physical reads
      19748  redo size
        857  bytes sent via SQL*Net to client
        864  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          5  sorts (memory)
          0  sorts (disk)
       1000  rows processed
SQL> SET AUTOTRACE ON
SQL> DELETE FROM t WHERE ROWNUM <= 1000;

1000 rows deleted.


Execution Plan
----------------------------------------------------------
Plan hash value: 325486485

--------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | DELETE STATEMENT    |      |     1 |     3   (0)| 00:00:01 |
|   1 |  DELETE             | T    |       |            |          |
|*  2 |   COUNT STOPKEY     |      |       |            |          |
|   3 |    TABLE ACCESS FULL| T    |     1 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------

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

   2 - filter(ROWNUM<=1000)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)


Statistics
----------------------------------------------------------
          8  recursive calls
       1036  db block gets
         15  consistent gets
          0  physical reads
     253264  redo size
        859  bytes sent via SQL*Net to client
        835  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
       1000  rows processed

SQL>
无索引插入和删除:

SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =354 hsecs
Time taken for DELETE =10244 hsecs

PL/SQL procedure successfully completed.
SQL> CREATE INDEX a_indx ON t(A);

Index created.

SQL>
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 't');

PL/SQL procedure successfully completed.
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =1112 hsecs
Time taken for DELETE =1474 hsecs

PL/SQL procedure successfully completed.

SQL>
现在,让我们首先截断表,将高水印设置回零

SQL> TRUNCATE TABLE t;

Table truncated.

SQL>
创建索引:

SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =354 hsecs
Time taken for DELETE =10244 hsecs

PL/SQL procedure successfully completed.
SQL> CREATE INDEX a_indx ON t(A);

Index created.

SQL>
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 't');

PL/SQL procedure successfully completed.
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =1112 hsecs
Time taken for DELETE =1474 hsecs

PL/SQL procedure successfully completed.

SQL>
收集表格统计信息:

SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =354 hsecs
Time taken for DELETE =10244 hsecs

PL/SQL procedure successfully completed.
SQL> CREATE INDEX a_indx ON t(A);

Index created.

SQL>
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 't');

PL/SQL procedure successfully completed.
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =1112 hsecs
Time taken for DELETE =1474 hsecs

PL/SQL procedure successfully completed.

SQL>
使用索引插入和删除:

SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =354 hsecs
Time taken for DELETE =10244 hsecs

PL/SQL procedure successfully completed.
SQL> CREATE INDEX a_indx ON t(A);

Index created.

SQL>
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 't');

PL/SQL procedure successfully completed.
SQL> DECLARE
  2    l_start NUMBER;
  3    l_loops NUMBER := 100000;
  4  BEGIN
  5
  6    l_start := DBMS_UTILITY.get_time;
  7
  8    FOR i IN 1 .. l_loops
  9    LOOP
 10      INSERT INTO t
 11        (a
 12        ) VALUES
 13        (i
 14        );
 15    END LOOP;
 16
 17    COMMIT;
 18
 19    DBMS_OUTPUT.put_line('Time taken for INSERT =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 20
 21    l_start := DBMS_UTILITY.get_time;
 22
 23    FOR i IN 1 .. l_loops
 24    LOOP
 25      DELETE FROM t WHERE a = i;
 26    END LOOP;
 27
 28    COMMIT;
 29
 30    DBMS_OUTPUT.put_line('Time taken for DELETE =' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
 31
 32  END;
 33  /
Time taken for INSERT =1112 hsecs
Time taken for DELETE =1474 hsecs

PL/SQL procedure successfully completed.

SQL>

因此,在任何一种情况下,删除操作所需的时间都比插入操作所需的时间长

删除操作所需的时间比插入操作所需的时间长有两个原因:

主要的一点是DELETE是一个查询:数据库必须找到要删除的记录。你的陈述是正确的

“删除,
其中cdate>201411

如果CDATE被索引,那充其量就是索引范围扫描。如果它没有索引,那么它是一个完整的表扫描。但是,如果CDATE的聚类因子很差,那么索引读取的性能可能不如完整表扫描。调优DELETE与调优SELECT语句非常相似

无论哪种方式,这都比插入记录所需的读取量大得多。为什么数据库会这样做?因为需要撤销。回滚时,数据库使用UNDO表空间中的信息来反转语句。对于INSERT,撤消操作是一个删除操作,因此它只需要插入行的ROWID。而撤销删除需要重新插入记录,因此整行必须存储在UNDO中

因此,DELETE操作必须检索整行并将其存储在UNDO中。记录越长,撤消管理的开销就越大。(相比之下,ROWID在插入时是一个微小的固定开销。)

类似地,(正如@lalitKumar指出的),对于删除,重做日志卷可能要大得多。OraFAQ有一些问题


外键可能会影响插入和删除:插入必须检查引用表中是否存在键,而删除必须检查从属表中是否存在引用。这将唯一键查找与非唯一甚至未索引的列进行比较。

您的问题与前面讨论的主题类似。我认为答案仍然是真实的

根据经验,我会说更新通常比 删除

如前所述,更新所做的工作比删除所做的工作要少。但是 这在很大程度上取决于更新是如何进行的,以及表结构是如何进行的 因为删除是

下面是数据库在执行每一步时将执行的一些步骤 指挥部。这些步骤并不完整,但它们有助于 照片

更新

  • 锁定记录/块
  • 执行before update语句触发器
  • 对于每一行,执行更新前行触发器
  • 检查列是否存在(唯一/检查)约束
  • 更改数据
  • 如果新值不再适合当前块,请为表添加新块(行链接)。这种情况经常发生在你

  • 将列值从5个字符更新为1000个字符

  • 更改/更新此列上的所有索引
  • 对于每一行,执行更新后的行触发器
  • 执行after update语句触发器

    删除

  • 锁定记录/块
  • 执行before delete语句触发器
  • 对于每一行,执行更新前行触发器
  • 检查是否有指向此表的FK
  • 如果是,请在所有明细表上进行选择,以查看是否存在子记录
  • 根据FK,删除孩子或生成错误消息
  • 将该行标记为已删除。根据pctfree和类似的存储参数,释放空间以供将来插入
  • 更改此表上的所有索引
  • 对于每一行,执行after delete row触发器
  • 执行after delete语句触发器
这甚至不包括撤消信息

总的来说,我认为为删除所做的大多数操作都更简单 比更新更昂贵。特别是对于未编制索引的 仅添加/更改1个字符的列

然而,更新/删除通常不是限制因素,而是 在更新之前发生并查找所有行的选择 这需要改变


删除或截断也需要同样的时间吗?问:是什么让你认为“删除”必然比“插入”(或者,就此而言,“更新”)需要更长的时间?问:所讨论的表是否同时具有触发器和索引?发生了什么