There was a question on Stack Overflow why does delete take longer than insert.
The question is too broad to be addressed as there could be many reasons and statistics behind the two operations. However, the question was asked very generally. And in general, it is true with most of the RDBMS. A DELETE is slower compared to an INSERT operation.
Let’s get into the details.
The autotrace statistics are good enough to find few reasons straight away.
Setup
SQL> CREATE TABLE t
2 (A NUMBER
3 );
Table created.
SQL>
INSERT autotrace statistics
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>
DELETE autotrace statistics
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>
When you DELETE a row the whole row goes to rollback segments and is also written into redo log.
When you do an INSERT the redo size is quite less compared to a DELETE.
Let’s do a small test, I will use DBMS_UTILITY.get_time to compare the timings. I will do a test first with an index, another without an index.
INSERT and DELETE without index:
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.
Now, let’ first TRUNCATE the table to set the HIGH WATERMARK back to zero.
SQL> TRUNCATE TABLE t;
Table truncated.
SQL>
Create an index:
SQL> CREATE INDEX a_indx ON t(A);
Index created.
SQL>
Gather table stats:
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 't');
PL/SQL procedure successfully completed.
INSERT and DELETE with index:
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>
So, in either case, DELETE operation takes longer than INSERT.
Hope it helps!
Filed under: Oracle Performance Tuning Tagged: delete, DELETE slower than INSERT, DELETE takes longer than INSERT, DELETE vs INSERT, insert, performance, performance between DELETE and INSERT, performance of delete versus insert
