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