3

PostgreSQL のバージョンは 9.0 です。

plpgsql 関数を最適化する必要があります。アイデアは、すべてのドキュメントを実行して、テーブル内の関連する行 902,903,905,907 がwebdte.doc_tip_cifra既に存在するかどうかをテストすることです。まだ存在しない場合は、後で検証を満たすために null 行を挿入します。4 つの条件の 1 つだけを使用し、実行する必要がある行の量の半分を使用しても、現時点ではとてつもなく遅いです。パフォーマンスを向上させるためのアイデアはありますか?

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;

doc_tip_cifraすべてのドキュメントに対するこのばかげた高価なループを回避し、ドキュメントごとに 4 回テストするために、ドキュメントの挿入ごとに 4 つの null 行を挿入する挿入トリガーを決定することをお勧めします。どう思いますか?

4

1 に答える 1

2

結局のところ、実際にはカウントは必要ありません。あなたの前の質問はその印象を伝えました。ただし、私のソリューションで置き換えるだけsumでは、それほど遠くはありません。max

はい、機能しますが、非常に非効率的です。一致する行が見つかった後、テーブルの残りを実行する必要はありません。それがEXISTS準結合の目的です。このまったく異なるアプローチを提案します。

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 として実行することができます。

前の質問とは別に、これはおそらく適切なインデックスを利用できます。最適なのは、次のような複数列のインデックスです。

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

クエリを非常に高速にする必要があります。

また、この種のアルゴリズムには、同時実行性に関する固有の問題があります。行がすでに存在するかどうかを確認してから挿入するまでの時間枠は、できるだけ短くする必要があります。この点では、すべてを 1 つのクエリに入れるのが最適です。

それでも完璧ではありません。データベースで多くの同時実行が見られる場合は、@depesz によるこの優れたブログ投稿に興味があるか、この関連する質問の下で詳細を読んでください。


はい、それをトリガーで解決するのは良い考えのように思えます。私はそれをします。

于 2012-07-24T03:09:55.027 に答える