Как вставить строку в таблицу без многократных запросов max (column_name) +1? - PullRequest
0 голосов
/ 27 октября 2019

У меня есть таблица, куда данные должны быть вставлены следующим образом:

SEQ      NAME      RUN_SL DOC_SL    DATE
1        UNIX       1       1    26/10/2019
2        UNIX       1       2    26/10/2019
3        UNIX       1       3    26/10/2019
4        ABCOP      2       1    26/10/2019
5        ABCOP      2       2    26/10/2019
6        TESLA      1       1    27/10/2019
7        LETHA      1       2    27/10/2019 
8        TESLA      2       1    27/10/2019
9        NEWBE      2       2    27/10/2019

Данные должны быть вставлены день ото дня. Пользователь может вставить несколько строк одновременно. В этом случае RUN_SL будет таким же, но DOC_SL будет увеличен. Чтобы достичь этого, я всегда должен был выглядеть так:

SELECT NVL(MAX(A.RUN_SL), 0) + 1, NVL(MAX(A.DOC_SL), 0) + 1
INTO V_RUN_SL, V_DOC_SL
FROM TEST_TBL A
WHERE A.DATE = SYSDATE;

Затем нужно было вставить данные с помощью цикла:

FOR DATA_LIST..COUNT:
 INSERT INTO TEST_TBL
 VALUES(
   TBL_SEQ.NEXTVAL,
   DATA_LIST(i).NAME,
   V_RUN_SL,
   V_DOC_SL,
   SYSDATE
 );

Я знаю, что будут проблемы с параллелизмом, связанные сNVL (MAX (Column_Name), 0) + 1. Чтобы добиться правильной вставки, как с ней справиться, а также искать альтернативные предложения для оптимизации запросов? Заранее спасибо.

1 Ответ

0 голосов
/ 28 октября 2019

Вместо того, чтобы задавать вопросы, я собираюсь сделать некоторые предположения:

  • «ДАТА» - это только часть даты, а часть времени в 00: 00: 00
  • Сегодня первый раз, когда кто-то вставляет одну или несколько строк, RUN_SL должен быть равен 1.
  • В следующий раз, когда кто-то вставляет несколько строк, RUN_SL должен быть равен 2.
  • Каждый раз, когда RUN_SL увеличивается, DOC_SL долженначать с 1.

Теперь несколько замечаний:

  • Вы используете SYSDATE. Если вам нужна только часть даты, используйте TRUNC (SYSDATE).
  • Чтобы сделать несколько вставок, используйте FORALL, а не FOR. FORALL вызовет движок SQL один раз, FOR вызовет его один раз в строке. Переключение между PL / SQL и SQL требует больших затрат ресурсов ЦП.
  • Чтобы избежать проблем параллелизма, вставки может выполнять только один сеанс за раз. Я использую простой механизм блокировки на технической таблице для сериализации операций.

Приведенный ниже код является простым подтверждением концепции. Входные данные жестко закодированы для вставки «UNIX» три раза.

С уважением, Stew Ashton

create table test_tbl(
  SEQ number primary key,
  NME varchar2(16),
  RUN_SL number,
  DOC_SL number,
  DTE date
);
create sequence TBL_SEQ;
create table tbl_lock(n primary key check(n=1)) as
select 1 from dual;

declare
  type t_name is record(nme test_tbl.nme%type);
  type tt_name is table of t_name;
  data_list tt_name := new tt_name();

  l_run_sl test_tbl.run_sl%type;

  type tt_num is table of number;
  lt_num tt_num := new tt_num();

  procedure lock_tbl is
    l_num number;
  begin
    select n into l_num
    from tbl_lock
    for update wait 3;
  end lock_tbl;

begin
  lock_tbl;
  data_list.extend(3);
  lt_num.extend(3);
  for i in 1..data_list.count loop
    data_list(i).nme := 'UNIX';
    lt_num(i) := i;
  end loop;  
  select nvl(max(run_sl), 0) + 1 into l_run_sl
  from test_tbl
  where dte = trunc(sysdate);
  forall i in 1..data_list.count
    insert into test_tbl (seq, nme, run_sl, doc_sl, dte)
      values(tbl_seq.nextval, data_list(i).nme, l_run_sl, lt_num(i), trunc(sysdate));
end;
/
commit;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...