Как повысить производительность при вставке более 40 тыс. строк

#sql #oracle #plsql

Вопрос:

 CREATE TABLE new_details_staging  (  e_id NUMBER(10),  e_name VARCHAR2(30),  portal_desc VARCHAR2(50),  risk_dec VARCHAR2(50),  CONSTRAINT pk_new_details_staging PRIMARY KEY (e_id) );  INSERT INTO new_details_staging  VALUES (11, 'A', 'AA', 'High');  INSERT INTO new_details_staging  VALUES (22, 'B', 'BB', 'Low');  CREATE TABLE lookup_ref  (  ref_id NUMBER(10),  ref_typ VARCHAR2(30),  ref_typ_desc VARCHAR2(20),  CONSTRAINT pk_lookup_ref PRIMARY KEY (ref_id) );  INSERT INTO lookup_ref  VALUES (181, 'portal', 'AA');  INSERT INTO lookup_ref  VALUES (182, 'portal', 'BB');  INSERT INTO lookup_ref  VALUES (183, 'risk', 'High');  INSERT INTO lookup_ref  VALUES (184, 'risk', 'Low');  CREATE TABLE new_details_main  (  e_id NUMBER(10),  e_name VARCHAR2(30),  portal NUMBER(20),  risk NUMBER(20),  CONSTRAINT pk_new_details_main PRIMARY KEY (e_id) );  COMMIT;  

Моя попытка:

 INSERT INTO new_details_main (e_id, e_name, portal,risk)  SELECT   n.e_id,  n.e_name,  (SELECT lr.ref_id  FROM lookup_ref lr  WHERE lr.ref_typ = 'portal'  AND lr.ref_typ_desc = n.portal_desc),  (SELECT lr.ref_id  FROM lookup_ref lr  WHERE lr.ref_typ = 'risk'  AND lr.ref_typ_desc = n.risk_dec)  FROM   new_details_staging n;  

В настоящее время я вставляю несколько записей, и это дает точные результаты, но на самом деле существует более 40 тысяч записей, поэтому я считаю, что это также приведет к проблемам с производительностью. Есть ли какой-нибудь способ вставить записи быстрее, потому что я напишу процедуру для этой вставки? Есть ли какой-либо другой способ, с помощью которого я могу написать запрос на вставку внутри процедуры?

Комментарии:

1. Если вставка 40 тысяч строк (в реляционной базе данных нет «записей») занимает больше секунды или около того, значит, что-то не так. Либо вы делаете это исключительно плохо, либо на самом деле это намного больше, чем 40 тысяч строк. 40 тысяч строк для вставки-ЭТО НИЧЕГО.

2. Есть ли триггеры, индексы в новой таблице? Если вы запустите инструкцию select без вставки, как будет выглядеть ее производительность и план выполнения?

3. Итак, new_details_main у вас есть еще много записей ? как насчет new_details_staging . Можете ли вы дать нам количество таблиц, чтобы дать нам представление ?

4. Вставка, которая у вас есть, выглядит разумно. Это на самом деле медленно, или вы просто ищете указатели на случай, если это так?

5. @mathguy Спасибо, что изучили это. На самом деле в нем было 40 тысяч записей, но можно вставить столько строк за считанные секунды, как показал Коннор в примере с 80 тысячами строк. Так что у меня все хорошо с этим 🙂

Ответ №1:

На моем ноутбуке мы можем достаточно легко масштабировать ваш тест

 SQLgt; SQLgt; CREATE TABLE new_details_staging  2 (  3 e_id NUMBER(10),  4 e_name VARCHAR2(30),  5 portal_desc VARCHAR2(50),  6 risk_dec VARCHAR2(50),  7 CONSTRAINT pk_new_details_staging PRIMARY KEY (e_id)  8 );  Table created.  SQLgt; SQLgt; INSERT INTO new_details_staging VALUES (11, 'A', 'AA', 'High');  1 row created.  SQLgt; INSERT INTO new_details_staging VALUES (22, 'B', 'BB', 'Low');  1 row created.  SQLgt; SQLgt; insert into new_details_staging  2 select e_id*500000 rownum, e_name, portal_desc, risk_dec  3 from new_details_staging,  4 ( select 1 from dual connect by level lt;= 400000 );  800000 rows created.  SQLgt; SQLgt; CREATE TABLE lookup_ref  2 (  3 ref_id NUMBER(10),  4 ref_typ VARCHAR2(30),  5 ref_typ_desc VARCHAR2(20),  6 CONSTRAINT pk_lookup_ref PRIMARY KEY (ref_id)  7 );  Table created.  SQLgt; SQLgt; INSERT INTO lookup_ref VALUES (181, 'portal', 'AA');  1 row created.  SQLgt; INSERT INTO lookup_ref VALUES (182, 'portal', 'BB');  1 row created.  SQLgt; INSERT INTO lookup_ref VALUES (183, 'risk', 'High');  1 row created.  SQLgt; INSERT INTO lookup_ref VALUES (184, 'risk', 'Low');  1 row created.  SQLgt; SQLgt; CREATE TABLE new_details_main  2 (  3 e_id NUMBER(10),  4 e_name VARCHAR2(30),  5 portal NUMBER(20),  6 risk NUMBER(20),  7 CONSTRAINT pk_new_details_main PRIMARY KEY (e_id)  8 );  Table created.  SQLgt; SQLgt; set timing on SQLgt; INSERT INTO new_details_main (e_id, e_name, portal,risk)  2 SELECT  3 n.e_id,  4 n.e_name,  5 (SELECT lr.ref_id  6 FROM lookup_ref lr  7 WHERE lr.ref_typ = 'portal'  8 AND lr.ref_typ_desc = n.portal_desc),  9 (SELECT lr.ref_id  10 FROM lookup_ref lr  11 WHERE lr.ref_typ = 'risk'  12 AND lr.ref_typ_desc = n.risk_dec)  13 FROM  14 new_details_staging n;  800002 rows created.  Elapsed: 00:00:02.97 SQLgt; SQLgt;  

Таким образом, около 3 секунд для 800 000 строк. Я думаю, с тобой все будет в порядке 🙂

Если поиск всегда верен и ключ сохранен, вы можете получить некоторую выгоду, перейдя в соединение, например

 SQLgt; set timing on SQLgt; INSERT INTO new_details_main (e_id, e_name, portal,risk)  2 SELECT  3 n.e_id,  4 n.e_name,  5 lr.ref_id,  6 lr1.ref_id  7 FROM  8 new_details_staging n,  9 lookup_ref lr,  10 lookup_ref lr1  11 where lr.ref_typ = 'portal'  12 AND lr.ref_typ_desc = n.portal_desc  13 and lr1.ref_typ = 'risk'  14 AND lr1.ref_typ_desc = n.risk_dec ;  800002 rows created.  Elapsed: 00:00:02.64  

Комментарии:

1. Спасибо за это. Я исходил из предположения, что слияние происходит намного быстрее, чем вставка. Но, как вы показали на примере, который мне помог