Используйте предложение WITH внутри хранимой процедуры - PullRequest
0 голосов
/ 05 июля 2018

Я хочу использовать предложение WITH для заполнения таблицы внутри хранимой процедуры. Я читал, что указанное предложение сохраняет данные в памяти, пока сеанс жив.

Есть таблица, в которой есть информация, которую мне нужно обновить, которая называется sprlink, но эта таблица содержит миллионы записей. В настоящее время у меня есть следующее обновление, но оно очень медленное:

open act_rpt_list_cdo;
loop
  fetch act_rpt_list_cdo bulk collect into v_act_rpt_list_cdo limit 100;
  for i in 1 .. v_act_rpt_list_cdo.count loop
    update RPT_LIST_CDO set name_cdo=(select trim(sln.linkvalue) from sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 164 and logidto=0),
                            date_cdo=(select trim(sln.linkvalue) from sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 165 and logidto=0),
                            cod_cdo=(select trim(sln.linkvalue) from sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 166 and logidto=0),
                            log_cdo=(select trim(sln.linkvalue) from sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 167 and logidto=0),
                            data_cdo=(select trim(sln.linkvalue) from sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 168 and logidto=0)

    where rowid=v_act_rpt_list_cdo(i).ri;
  end loop;
  exit when act_rpt_list_cdo%notfound;
end loop;
close act_rpt_list_cdo

Я хотел использовать в этом контексте предложение, ограничивающее записи, но я понятия не имею, как использовать его в процедуре:

WITH tt_sprlink AS (select sln.objectid as objectid , sln.linkid as linkid, trim(sln.linkvalue) linkvalue
   from sprlinks sln join RPT_LIST_CDO rpt on (sln.objectid=rpt.id and sln.logidto=0)
  where sln.linkid in (164,165,166,167,168))
select *
from tt_sprlink

Чтобы можно было что-то сделать следующим образом, поскольку tt_srplink будет содержать только необходимые записи для моего обновления.

act_rpt_list_cdo
loop
  fetch act_rpt_list_cdo bulk collect into v_act_rpt_list_cdo limit 100;
  for i in 1 .. v_act_rpt_list_cdo.count loop
    update RPT_LIST_CDO set name_cdo=(select trim(sln.linkvalue) from tt_sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 164),
                            date_cdo=(select trim(sln.linkvalue) from tt_sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 165),
                            cod_cdo=(select trim(sln.linkvalue) from tt_sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 166),
                            log_cdo=(select trim(sln.linkvalue) from tt_sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 167),
                            data_cdo=(select trim(sln.linkvalue) from tt_sprlink sln where sln.objectid=v_act_rpt_list_cdo(i).id  and SLN.LINKID = 168)

    where rowid=v_act_rpt_list_cdo(i).ri;
  end loop;
  exit when act_rpt_list_cdo%notfound;
end loop;
close act_rpt_list_cdo

Любое предложение или идею, пожалуйста?

1 Ответ

0 голосов
/ 06 июля 2018

Прежде всего: утверждение о том, что пункты WITH «хранят данные в памяти, пока сеанс жив», равно false . Конструкция WITH cursor_var AS (SELECT ...) LOOP - это просто цикл курсора - такой же, как у цикла OPEN..FETCH..CLOSE, который у вас есть. Тем не менее: WITH циклы курсора могут понравиться, но кэширование магических данных не входит в их число.

Во-вторых: если вы что-то не указали, то в этом случае нет необходимости в PL / SQL. Строковая обработка курсора, как у вас, будет намного медленнее, чем один оператор SQL. (Ваш случай еще хуже, потому что вы делаете 5 скалярных подзапросов для каждого обновления).

Вот как вы можете достичь своей цели, используя одно выражение UPDATE:

UPDATE rpt_list_cdo u
SET ( name_cdo, date_cdo, cod_cdo, log_cdo, data_cdo ) = 
(
SELECT MAX(DECODE(sln.linkid,164,trim(sln.linkvalue),null)) name_cdo,
       MAX(DECODE(sln.linkid,165,trim(sln.linkvalue),null)) date_cdo,
       MAX(DECODE(sln.linkid,166,trim(sln.linkvalue),null)) cod_cdo,
       MAX(DECODE(sln.linkid,167,trim(sln.linkvalue),null)) log_cdo,
       MAX(DECODE(sln.linkid,168,trim(sln.linkvalue),null)) data_cdo
FROM   sprlinks sln
WHERE  sln.objectid = u.id
AND    sln.linkid in (164,165,166,167,168))
WHERE 1=1
AND -- whatever other conditions you have in your act_rpt_list_cdo cursor

MERGE также будет работать, но мне больше нравится UPDATE в этом случае, потому что легче добавить любые другие условия, которые есть в вашем act_rpt_list_cdo курсоре.

...