2012-07-24 3 views
3

Версия PostgreSQL составляет 9.0.Оптимизировать функцию plpgsql

Мне нужно оптимизировать функцию plpgsql. Идея состоит в том, чтобы просто запустить все документы и проверить, существуют ли соответствующие строки 902,903,905,907 в таблице webdte.doc_tip_cifra. Если они еще не существуют, вставьте нулевые строки, чтобы впоследствии выполнить проверку. Это смехотворно медленно в данный момент, даже если я использую только один из 4 условий и использую половину количества строк, с которыми он должен работать. У кого-нибудь есть идея повышения производительности?

CREATE OR REPLACE FUNCTION webdte.addtagobligatoriosventa(idlibro bigint) 
    RETURNS character AS 
$BODY$ 
DECLARE     
    id_documento bigint; 
    validador integer; 
    validador1 integer; 
    validador2 integer; 
    validador3 integer; 
    validador4 integer; 

    tipo_cifra integer; 
    --counts integer[]; 
BEGIN 
    SELECT INTO validador1, validador2, validador3, validador4 
      max(CASE id_tipo_cifra WHEN 901 THEN 1 ELSE 0 END) 
      ,max(CASE id_tipo_cifra WHEN 902 THEN 1 ELSE 0 END) 
      ,max(CASE id_tipo_cifra WHEN 905 THEN 1 ELSE 0 END) 
      ,max(CASE id_tipo_cifra WHEN 907 THEN 1 ELSE 0 END) 
    FROM webdte.doc_tip_cifra 
    WHERE id_doc = id_documento; 

    if (validador1 = 0) then 
     insert into webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
     values (id_documento, 901, 0, 0); 

    end if; 
     if (validador2 = 0) then 
     insert into webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
     values (id_documento, 902, 0, 0); 

    end if; 
     if (validador3 = 0) then 
     insert into webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
     values (id_documento, 905, 0, 0); 

    end if; 
     if (validador4 = 0) then 
     insert into webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
     values (id_documento, 907, 0, 0); 

    end if; 

END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE; 

Может быть, лучше решить для запуска вставки, которая вставляет 4 нулевых строки на doc_tip_cifra на каждом документ вставке, чтобы избежать этого глупого дорогой цикл по всем документам и тест 4 раза для каждого документа? Как вы думаете?

ответ

2

Оказывается, вам не нужен счет. Ваше сообщение preceding question передало это впечатление. Однако в моем решении вам не нужно просто заменить summax.

Это работает, да, но это безумно неэффективно. После того, как вы нашли подходящую строку, вам не нужно пробегать всю оставшуюся часть таблицы. Вот что такое EXISTS semi-joins. Я предлагаю это совершенно другой подход:

INSERT INTO webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
SELECT id_documento, 901, 0, 0 
WHERE NOT EXISTS (
    SELECT 1 
    FROM webdte.doc_tip_cifra 
    WHERE id_doc = id_documento 
    AND id_tipo_cifra = 901 
    ); 

INSERT INTO webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
SELECT id_documento, 902, 0, 0 
WHERE NOT EXISTS (
    SELECT 1 
    FROM webdte.doc_tip_cifra 
    WHERE id_doc = id_documento 
    AND id_tipo_cifra = 902 
    ); 

INSERT INTO webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
SELECT id_documento, 905, 0, 0 
WHERE NOT EXISTS (
    SELECT 1 
    FROM webdte.doc_tip_cifra 
    WHERE id_doc = id_documento 
    AND id_tipo_cifra = 905 
    ); 

INSERT INTO webdte.doc_tip_cifra (id_doc, id_tipo_cifra, tasa_imp, val_imp) 
SELECT id_documento, 907, 0, 0 
WHERE NOT EXISTS (
    SELECT 1 
    FROM webdte.doc_tip_cifra 
    WHERE id_doc = id_documento 
    AND id_tipo_cifra = 907 
    ); 

Вы можете обернуть это в plpgsql или SQL функции или вы можете просто запустить его как обычный SQL.

В отличие от предыдущего вопроса, это может, скорее всего, использовать подходящие индексы. Оптимальный будет multi-column index как:

CREATE INDEX doc_tip_cifra_special_idx 
ON webdte.doc_tip_cifra (id_doc, id_tipo_cifra); 

Если сделать ваши запросы молниеносно.

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

Тем не менее, это не отлично. Если ваша база данных видит много параллелизма, вас может заинтересовать этот excellent blog post by @depesz или более under this related question.


И да, решение этого с помощью триггера звучит как хорошая идея. Я бы сделал это.

+0

большое вам спасибо! Я просто изучаю postgres, и вы действительно открыли мне глаза с этим. круто.. – mugdiman

Смежные вопросы