Hi Team
At the time of writing this, on LiveSQL I get "500 Internal Server Error", so will just paste the re-producible code here.
I'm building sample application data for testing using PL/SQL.
For loading 10M data in USERS_MAPPING table, currently it is taking ~17min. Is there a way I can speed up the insert operation for USERS_MAPPING table.
Database: Oracle 12.2 EE
OEL version: 7.5
Appreciate your help.
Thanks..
-- Drop tables
DROP TABLE users_mapping PURGE;
DROP TABLE users PURGE;
-- Create table USERS
CREATE TABLE users
(
users_id VARCHAR2 (40 CHAR ) NOT NULL,
displayName VARCHAR2 (255 CHAR ) NOT NULL,
createdBy VARCHAR2 (255 CHAR ),
createdDate TIMESTAMP(6),
lastModifiedBy VARCHAR2 (255 CHAR ),
lastModifiedDate TIMESTAMP(6),
CONSTRAINT users_userid_pk PRIMARY KEY ( users_id )
)
;
-- Create table USERS_MAPPING
CREATE TABLE users_mapping
(
users_id VARCHAR2(40 CHAR) NOT NULL,
users_mapping_id VARCHAR2(40 CHAR) NOT NULL,
createdBy VARCHAR2 (255 CHAR ),
createdDate TIMESTAMP(6),
lastModifiedBy VARCHAR2 (255 CHAR ),
lastModifiedDate TIMESTAMP(6),
name VARCHAR2(255 CHAR) NOT NULL,
CONSTRAINT users_mapping_id_pk PRIMARY KEY ( users_id, users_mapping_id ),
CONSTRAINT users_mapping_userid_fk FOREIGN KEY ( users_id ) REFERENCES users ( users_id )
)
;
-- Load USERS table data
BEGIN
FOR i in 0..1000
LOOP
INSERT INTO users
VALUES (
SYS_GUID(),
'User-'||i,
'Admin',
SYSTIMESTAMP,
'Admin',
SYSTIMESTAMP
);
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20100,
'ORA Error Code =>'|| SQLERRM
|| CHR(10)
||'ORA Error Stack => '
|| SUBSTR (DBMS_UTILITY.FORMAT_ERROR_STACK,1,500)
|| CHR(10)
||'ORA Error Backtrace => '
|| SUBSTR (DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,1,500)
);
END;
/
-- Load USERS_MAPPING table data
DECLARE
TYPE t_users_id IS TABLE OF VARCHAR2(40);
v_users_id t_users_id:=t_users_id();
v_sql VARCHAR2(4000):=NULL;
BEGIN
SELECT users_id
BULK COLLECT INTO v_users_id
FROM users
ORDER BY users_id;
IF (v_users_id.COUNT>0) THEN
FOR i IN v_users_id.FIRST .. v_users_id.LAST
LOOP
FOR j in 1..10000
LOOP
v_sql := 'INSERT INTO users_mapping VALUES (:1, :2, :3, :4, :5, :6, :7)';
EXECUTE IMMEDIATE v_sql USING v_users_id(i), SYS_GUID(), 'Admin', SYSTIMESTAMP, 'Admin', SYSTIMESTAMP, 'Mapping'||j;
END LOOP;
COMMIT;
END LOOP;
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20100,
'ORA Error Code =>'|| SQLERRM
|| CHR(10)
||'ORA Error Stack => '
|| SUBSTR (DBMS_UTILITY.FORMAT_ERROR_STACK,1,500)
|| CHR(10)
||'ORA Error Backtrace => '
|| SUBSTR (DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,1,500)
);
END;
/
Without touching the indexes, you can achieve the following
SQL> CREATE TABLE users
2 (
3 users_id VARCHAR2 (40 CHAR ) NOT NULL,
4 displayName VARCHAR2 (255 CHAR ) NOT NULL,
5 createdBy VARCHAR2 (255 CHAR ),
6 createdDate TIMESTAMP(6),
7 lastModifiedBy VARCHAR2 (255 CHAR ),
8 lastModifiedDate TIMESTAMP(6),
9 CONSTRAINT users_userid_pk PRIMARY KEY ( users_id )
10 )
11 ;
Table created.
SQL>
SQL> CREATE TABLE users_mapping
2 (
3 users_id VARCHAR2(40 CHAR) NOT NULL,
4 users_mapping_id VARCHAR2(40 CHAR) NOT NULL,
5 createdBy VARCHAR2 (255 CHAR ),
6 createdDate TIMESTAMP(6),
7 lastModifiedBy VARCHAR2 (255 CHAR ),
8 lastModifiedDate TIMESTAMP(6),
9 name VARCHAR2(255 CHAR) NOT NULL,
10 CONSTRAINT users_mapping_id_pk PRIMARY KEY ( users_id, users_mapping_id ),
11 CONSTRAINT users_mapping_userid_fk FOREIGN KEY ( users_id ) REFERENCES users ( users_id ) deferrable
12 )
13 ;
Table created.
--
-- notice I made the constraint deferrable
--
SQL>
SQL> set constraint users_mapping_userid_fk deferred;
Constraint set.
SQL>
SQL> set timing on
SQL> insert into users
2 select
3 SYS_GUID(),
4 'User-'||rownum,
5 'Admin',
6 SYSTIMESTAMP,
7 'Admin',
8 SYSTIMESTAMP
9 from dual connect by level <= 1000;
1000 rows created.
Elapsed: 00:00:00.13
SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
SQL>
SQL> insert /*+ APPEND */ into users_mapping
2 select u.users_id, SYS_GUID(), 'Admin', SYSTIMESTAMP, 'Admin', SYSTIMESTAMP, 'Mapping'||r
3 from users u,
4 ( select rownum r from dual connect by level <= 1000 );
1000000 rows created.
Elapsed: 00:00:54.88
SQL>
Now that only did 1000 rows into users_mapping for each user. Before moving onto your 10,000 per user, I'll now change to doing the index maintenance *after* the load
SQL> CREATE TABLE users
2 (
3 users_id VARCHAR2 (40 CHAR ) NOT NULL,
4 displayName VARCHAR2 (255 CHAR ) NOT NULL,
5 createdBy VARCHAR2 (255 CHAR ),
6 createdDate TIMESTAMP(6),
7 lastModifiedBy VARCHAR2 (255 CHAR ),
8 lastModifiedDate TIMESTAMP(6)
9 )
10 ;
Table created.
SQL>
SQL> CREATE TABLE users_mapping
2 (
3 users_id VARCHAR2(40 CHAR) NOT NULL,
4 users_mapping_id VARCHAR2(40 CHAR) NOT NULL,
5 createdBy VARCHAR2 (255 CHAR ),
6 createdDate TIMESTAMP(6),
7 lastModifiedBy VARCHAR2 (255 CHAR ),
8 lastModifiedDate TIMESTAMP(6),
9 name VARCHAR2(255 CHAR) NOT NULL
10 )
11 ;
Table created.
SQL> set timing on
SQL> insert into users
2 select
3 SYS_GUID(),
4 'User-'||rownum,
5 'Admin',
6 SYSTIMESTAMP,
7 'Admin',
8 SYSTIMESTAMP
9 from dual connect by level <= 1000;
1000 rows created.
Elapsed: 00:00:00.07
SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
SQL>
SQL> insert /*+ APPEND */ into users_mapping
2 select u.users_id, SYS_GUID(), 'Admin', SYSTIMESTAMP, 'Admin', SYSTIMESTAMP, 'Mapping'||r
3 from users u,
4 ( select rownum r from dual connect by level <= 10000 );
10000000 rows created.
Elapsed: 00:03:47.17
SQL>
SQL> commit;
Commit complete.
Elapsed: 00:00:00.07
SQL>
SQL> alter table users add CONSTRAINT users_userid_pk PRIMARY KEY ( users_id );
Table altered.
Elapsed: 00:00:00.00
SQL> alter table users_mapping add CONSTRAINT users_mapping_id_pk PRIMARY KEY ( users_id, users_mapping_id );
Table altered.
Elapsed: 00:02:11.75
SQL> alter table users_mapping add CONSTRAINT users_mapping_userid_fk FOREIGN KEY ( users_id ) REFERENCES users ( users_id ) ;
Table altered.
Elapsed: 00:00:05.19
SQL>
SQL>
So that brings us down to around 5mins, and that is just on my laptop. But, also you'll find that most of this time is spent on CPU getting the GUID's. I've changed your example to using sequences, and look what happens
SQL> create sequence user_seq;
Sequence created.
SQL> create sequence users_mapping_seq cache 100000;
Sequence created.
SQL>
SQL> CREATE TABLE users
2 (
3 users_id VARCHAR2 (40 CHAR ) NOT NULL,
4 displayName VARCHAR2 (255 CHAR ) NOT NULL,
5 createdBy VARCHAR2 (255 CHAR ),
6 createdDate TIMESTAMP(6),
7 lastModifiedBy VARCHAR2 (255 CHAR ),
8 lastModifiedDate TIMESTAMP(6)
9 )
10 ;
Table created.
SQL>
SQL> CREATE TABLE users_mapping
2 (
3 users_id VARCHAR2(40 CHAR) NOT NULL,
4 users_mapping_id VARCHAR2(40 CHAR) NOT NULL,
5 createdBy VARCHAR2 (255 CHAR ),
6 createdDate TIMESTAMP(6),
7 lastModifiedBy VARCHAR2 (255 CHAR ),
8 lastModifiedDate TIMESTAMP(6),
9 name VARCHAR2(255 CHAR) NOT NULL
10 )
11 ;
Table created.
SQL>
SQL> set timing on
SQL> insert into users
2 select
3 user_seq.nextval,
4 'User-'||rownum,
5 'Admin',
6 SYSTIMESTAMP,
7 'Admin',
8 SYSTIMESTAMP
9 from dual connect by level <= 1000;
1000 rows created.
Elapsed: 00:00:00.03
SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
SQL>
SQL> insert /*+ APPEND */ into users_mapping
2 select u.users_id, users_mapping_seq.nextval, 'Admin', SYSTIMESTAMP, 'Admin', SYSTIMESTAMP, 'Mapping'||r
3 from users u,
4 ( select rownum r from dual connect by level <= 10000 );
10000000 rows created.
Elapsed: 00:00:18.24
SQL>
SQL> commit;
Commit complete.
Elapsed: 00:00:00.06
SQL> alter table users add CONSTRAINT users_userid_pk PRIMARY KEY ( users_id );
Table altered.
Elapsed: 00:00:00.04
SQL> alter table users_mapping add CONSTRAINT users_mapping_id_pk PRIMARY KEY ( users_id, users_mapping_id );
Table altered.
Elapsed: 00:00:20.78
SQL> alter table users_mapping add CONSTRAINT users_mapping_userid_fk FOREIGN KEY ( users_id ) REFERENCES users ( users_id ) ;
Table altered.
Elapsed: 00:00:01.47
Yes - that is 40 seconds total time.