我们有以下存储过程,它最近在 postgres db 中的大量日期上执行得非常慢。问题:
我们解析一个字符串的性质(第一个数字是行的id,第二个是状态)
||2|0||3|1||4|0||
用java这样的高级语言解析、拆分字符串和循环会更好吗?循环在 Postgres 中可以更有效吗?存储过程中的事务是如何处理的?整个功能是一笔交易?可能我们在数据库上做了很多写入和删除操作。删除也需要很长时间。可以更有效地处理吗?
CREATE OR REPLACE FUNCTION verificaemitidos(entrada text, largo_mensaje integer)
RETURNS character AS
$BODY$
DECLARE
texto_procesado text;
identificador bigint;
estado_mensaje int;
i int;
existe_documento int;
estado_documento text;
rut numeric;
tipo int;
folio_doc numeric;
otros_estados int;
BEGIN
--estado 1 insertado
--estado 0 no insertado
--mensaje id_documento|estado||id_documento|estado||
i := 1;
while (i <= largo_mensaje)
loop
--Proceso el mensaje
texto_procesado := split_part(entrada,'||', i) ;
identificador := split_part(texto_procesado, '|', 1);
estado_mensaje := split_part(texto_procesado, '|', 2);
-- Se comienza a hacer la comparacion
existe_documento := (select count (id) from uris_emitidos where id = identificador);
select estado, emp_rut, tipo_doc, folio into estado_documento, rut, tipo, folio_doc from uris_emitidos where id = identificador;
--si existe el documento
if (existe_documento > 0) then
--si el documento que se ingreso esta insertado
if (estado_mensaje = 1) then
--si esta aceptado se eliminan todos los documentos con ese rut, tipo, folio
if (estado_documento = 'A') then
delete from uris_emitidos where folio = folio_doc and emp_rut = rut and tipo_doc = tipo;
end if;
--si esta aceptado con reparo se eliminan todos los documentos con ese rut, tipo, folio
if (estado_documento = 'B') then
delete from uris_emitidos where folio = folio_doc and emp_rut = rut and tipo_doc = tipo;
end if;
--si esta rechazado se elimina el rechazado y el publicado
if (estado_documento = 'R') then
delete from uris_emitidos where folio = folio_doc and emp_rut = rut and tipo_doc = tipo and estado in ('R', 'P');
end if;
--si esta publicado se elimina
if (estado_documento = 'P') then
delete from uris_emitidos where id = identificador;
end if;
--si el documento que se ingreso no esta insertado
else
--si esta aceptado se actualiza para que el proceso lo re-encole
if (estado_documento = 'A') then
update uris_emitidos set estado_envio = 0, cont = (cont + 1) where id = identificador;
end if;
--si esta aceptado con reparo se actualiza para que el proceso lo re-encole
if (estado_documento = 'B') then
update uris_emitidos set estado_envio = 0, cont = (cont + 1) where id = identificador;
end if;
--si esta rechazado se verifica que no existe un registro aceptado que se haya encolado o este en espera de encolar
if (estado_documento = 'R') then
otros_estados = (select count(id) from uris_emitidos ue where ue.folio = folio_doc and ue.emp_rut = rut and ue.tipo_doc = tipo and ue.estado in ('A', 'B'));
--si otros estados = 0 significa que el estado rechazado es el mejor estado que hay, por lo tanto se debe re-encolar
if (otros_estados = 0) then
update uris_emitidos set estado_envio = 0, cont = (cont + 1) where id = identificador;
end if;
end if;
--si esta rechazado se verifica que no existe un registro aceptado o rechazado que se haya encolado o este en espera de encolar
if (estado_documento = 'P') then
otros_estados = (select count(id) from uris_emitidos where folio = folio_doc and emp_rut = rut and tipo_doc = tipo and estado in ('A', 'B', 'R'));
--si otros estados = 0 significa que el estado rechazado es el mejor estado que hay, por lo tanto se debe re-encolar
if (otros_estados = 0) then
update uris_emitidos set estado_envio = 0, cont = (cont + 1) where id = identificador;
end if;
end if;
end if;
end if;
i := i+1;
end loop;
return 'ok';
END;
$BODY$
LANGUAGE plpgsql VOLATILE;