> https://medium.com/@ramazan.ozdemir/bulk-operations-in-oracle-database-bulk-insert-bulk-update-and-bulk-delete-0a1b9074cb0e Setup: ```sql create user if not exists SAMPLE no authentication; grant connect, resource, unlimited tablespace to SAMPLE; drop table if exists SAMPLE.RANDOM_DATA_LOAD purge; create table SAMPLE.RANDOM_DATA_LOAD ( id_col NUMBER, text_col VARCHAR2(30), date_col DATE ); SET SERVEROUTPUT ON; DECLARE -- Parameters v_total_rows NUMBER := 10000000; -- Total lines to insert v_start_date DATE := DATE '2020-01-01'; -- Range start v_end_date DATE := DATE '2025-12-31'; -- Range end -- Internal variables v_date_range NUMBER; BEGIN v_date_range := v_end_date - v_start_date; FOR i IN 1 .. v_total_rows LOOP INSERT INTO SAMPLE.RANDOM_DATA_LOAD ( id_col, text_col, date_col ) VALUES ( i, -- Distinct integer DBMS_RANDOM.STRING('A', 30), -- Random string (Alphanumeric) v_start_date + DBMS_RANDOM.VALUE(0, v_date_range) -- Random date in range ); -- Optional: Commit every 10,000 rows to keep undo logs manageable IF MOD(i, 10000) = 0 THEN COMMIT; END IF; END LOOP; COMMIT; DBMS_OUTPUT.PUT_LINE('Successfully inserted ' || v_total_rows || ' rows.'); END; / alter table SAMPLE.RANDOM_DATA_LOAD add constraint RANDOM_DATA_LOAD_PK PRIMARY KEY (id_col); exec dbms_stats.gather_table_stats(ownname=>'SAMPLE',tabname=>'RANDOM_DATA_LOAD',method_opt=>'for all columns size AUTO'); ``` Bulk delete: ```sql var my_action VARCHAR2(30); exec :my_action:='bulk delete'; @login select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => :my_action); DECLARE TYPE id_col_table_type IS TABLE OF SAMPLE.RANDOM_DATA_LOAD.id_col%TYPE; id_col_table id_col_table_type; BEGIN -- Retrieve data to be deleted in bulk SELECT id_col BULK COLLECT INTO id_col_table FROM SAMPLE.RANDOM_DATA_LOAD WHERE date_col <= date'2022-06-15'; -- Perform bulk delete FORALL i IN 1..id_col_table.COUNT DELETE FROM SAMPLE.RANDOM_DATA_LOAD WHERE id_col = id_col_table(i); COMMIT; END; / select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => NULL); ``` Classic delete 1: ```sql var my_action VARCHAR2(30); exec :my_action:='classic delete 1'; @login select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => :my_action); delete from SAMPLE.RANDOM_DATA_LOAD where id_col in (select id_col from SAMPLE.RANDOM_DATA_LOAD WHERE date_col <= date'2022-06-15'); select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => NULL); ``` Classic delete 2: ```sql var my_action VARCHAR2(30); exec :my_action:='classic delete 2'; @login select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => :my_action); delete from SAMPLE.RANDOM_DATA_LOAD where date_col <= date'2022-06-15'; select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => NULL); ``` ``` bulk delete ----------- DELETE FROM SAMPLE.RANDOM_DATA_LOAD WHERE ID_COL = :B1 Elapsed CPU IO End Plan Buffer time time time Snap snaphot hash 0ptimizer Buffer gets SQL Disk /exec /exec /exec Elig Inter Instance Id time value cost #Ex #EOF gets /exec Prof Px reads (sec) (sec) (sec) Mb Mb #Rows -------- -------- ----------- ---------- ---------- -------- -------- ---------- ----------- ---- ------ ---------- ------- ----- ------ ------- ------- ---------- NABOOPRD 3 01/05 15:49 2400881684 2 1 1 20971850 20971850 0 83 170 103 0 0 1 4089976 classic delete 1 ---------------- Elapsed CPU IO End Plan Buffer time time time Snap snaphot hash 0ptimizer Buffer gets SQL Disk /exec /exec /exec Elig Inter Instance Id time value cost #Ex #EOF gets /exec Prof Px reads (sec) (sec) (sec) Mb Mb #Rows -------- -------- ----------- ---------- ---------- -------- -------- ---------- ----------- ---- ------ ---------- ------- ----- ------ ------- ------- ---------- NABOOPRD 4 01/05 16:03 1336456799 18858 1 1 12570950 12570950 0 22165 93 52 0 0 173 4089976 classic delete 2 ---------------- Elapsed CPU IO End Plan Buffer time time time Snap snaphot hash 0ptimizer Buffer gets SQL Disk /exec /exec /exec Elig Inter Instance Id time value cost #Ex #EOF gets /exec Prof Px reads (sec) (sec) (sec) Mb Mb #Rows -------- -------- ----------- ---------- ---------- -------- -------- ---------- ----------- ---- ------ ---------- ------- ----- ------ ------- ------- ---------- NABOOPRD 5 01/05 16:18 1336456799 18858 1 1 12562664 12562664 0 25260 91 51 0 0 197 4089976 ``` ```sql var my_action VARCHAR2(30); exec :my_action:='bulk insert'; @login select sysdate from dual; exec DBMS_APPLICATION_INFO.SET_ACTION (action_name => :my_action); DECLARE -- Configuration v_start_val INTEGER := 20000000; v_count INTEGER := 10000000; -- Define the collection type TYPE t_int_tab IS TABLE OF INTEGER INDEX BY PLS_INTEGER; v_numbers t_int_tab; BEGIN -- 1. Manual Loop to populate the variable -- This replaces the "BULK COLLECT" step with procedural logic FOR i IN 1 .. v_count LOOP v_numbers(i) := v_start_val + (i - 1); END LOOP; FORALL i IN 1..v_numbers.COUNT INSERT INTO SAMPLE.RANDOM_DATA_LOAD VALUES(v_numbers(i),'bulk insert',sysdate); commit; END; / select sysdate from dual; ``` ``` SQL_TEXT ------------------------------------------------------------------------- INSERT INTO SAMPLE.RANDOM_DATA_LOAD VALUES(:B1 ,'bulk insert',SYSDATE) Elapsed CPU IO End Plan Buffer time time time Snap snaphot hash 0ptimizer Buffer gets SQL Disk /exec /exec /exec Elig Inter Instance Id time value cost #Ex #EOF gets /exec Prof Px reads (sec) (sec) (sec) Mb Mb #Rows -------- -------- ----------- ---------- ---------- -------- -------- ---------- ----------- ---- ------ ---------- ------- ----- ------ ------- ------- ---------- NABOOPRD 21 02/05 09:53 0 1 1 1 918750 918750 0 2 72 15 0 0 0 10000000 ```