web-dev-qa-db-ja.com

md5(JSONB_COLUMN :: text)のUNIQUE制約でINSERTパフォーマンスを最適化します

次の表とインデックスを定義しています。

_CREATE TABLE IF NOT EXISTS data (
    id serial,
    job_id bigint NOT NULL,
    payload jsonb NOT NULL,
    tags jsonb NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_data_content on data (md5(payload::text));
CREATE INDEX IF NOT EXISTS idx_data_tags ON data USING GIN (tags jsonb_path_ops);
CREATE INDEX IF NOT EXISTS idx_data_jid ON data USING btree (job_id);
_

そのテーブルには、_job_id_(_payload->>'jobId'_でも使用可能)および_payload->>'__time'_に格納されているタイムスタンプ(UNIXエポック)に関連付けられている多くのJSON BLOBを格納しています。重複するJSONブロブの保存を避けたいので、_ このメソッドUNIQUE制約として使用しています。ただし、DBで数十万行を超えると、INSERTパフォーマンスが低下し始めます。これは、UNIQUE制約なしでは起こりません。

ほとんどありませんが、same_job_id__payload->>'__time'_。たとえば、最初に_job_id_をチェックし、次に_payload->>'__time'_をチェックするUNIQUE制約を定義して、両方が実際にmd5(payload::text)インデックス?

(JSON BLOBのキーは、同じドキュメントに対して常に同じ順序であることに注意してください。)

1
janoliver

一意性制約だけが問題である場合(そして、上記の説明で理由を詳しく知りたい場合)、ここにアイデアがあります。

  • 一意性制約を削除する
  • 読み取り(選択)を行うときは、order by id asc limit 1重複を無視する
  • ある種の並列プロセスが定期的にテーブルを通過し、重複を削除する
1
John Bachir

ここにいくつかのアイデアがあります。
関数の制約チェックを行います。
2番目はテーブルを変更し、欠落データを追加するトリガーを作成し、チェックする必要がある3つのフィールドに新しいインデックスを作成します

CREATE TRIGGER check_jsonb
    BEFORE INSERT  
    ON data
    FOR EACH ROW
    EXECUTE PROCEDURE 

CREATE FUNCTION public._check_jsonb()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
AS $BODY$
    declare

    _check_rec record;

    begin
        select job_id, payload from data where job_id = new.job_id 
        if found then
            if _check.payload.__time == new.jsonb.__time  
                  --do not know json command in postgresql 
                  -- that well to extract this value
                select true from data where new.payload == (md5(payload::text)) 
            end if;
        end if ;
        return new;
$BODY$

-試す2番目のアイデア

CREATE TABLE IF NOT EXISTS data (
    id serial,
    job_id bigint NOT NULL,
    payload jsonb NOT NULL,
    tags jsonb NULL,
    hash_check text not null, 
    time timestamp not null 
);
create unique index if not exists idx_jobid_time on data (id, time, hash_check);
CREATE INDEX IF NOT EXISTS idx_data_tags ON data USING GIN (tags jsonb_path_ops);
CREATE INDEX IF NOT EXISTS idx_data_jid ON data USING btree (job_id);

CREATE TRIGGER check_jsonb_idea2
    BEFORE INSERT  or Update
    ON data
    FOR EACH ROW
    EXECUTE PROCEDURE 

CREATE FUNCTION public._check_jsonb_idea2()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
AS $BODY$
    begin 
        new.time = new.jsonb.__time ;-- do not know json commands very while extract this 
        new.hash_check = (md5(payload::text)) 
        return new;
    end;
$BODY$

これにより、他のインデックスを削除することもできます

1
zsheep