AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 253891
Accepted
Morris de Oryx
Morris de Oryx
Asked: 2019-11-22 21:03:30 +0800 CST2019-11-22 21:03:30 +0800 CST 2019-11-22 21:03:30 +0800 CST

Projeto de tabela de histórico para exclusões no PG 11.5

  • 772

Tenho uma dúvida sobre o design de uma tabela de histórico no Postgres.

A configuração é que eu tenho uma tabela que contém uma lista de necessidades. Um local recalcula os itens sob demanda a cada cinco minutos e envia essa lista para o Postgres. A lista "quente" atual é então acessível a vários aplicativos cliente para puxar. Portanto, a cada cinco minutos, as linhas relacionadas a um local específico são excluídas e repovoadas com o que está quente. Imagine uma tela na parede de um armazém onde as pessoas olham para cima para ver tarefas urgentes, esse tipo de coisa. Esta é mais ou menos uma tabela de filas/avisos, não uma tabela de armazenamento real.

O que estamos rastreando na lista de itens sob demanda são peças específicas, com IDs. É valioso para nós coletar dados (ou pelo menos estatísticas) ao longo do tempo. Podemos descobrir que itens específicos aparecem na lista todos os dias, enquanto outros aparecem apenas raramente. Isso pode ajudar a orientar as escolhas de compra e tal.

Esse é o plano de fundo, estou no Postgres 11.5, então sem colunas geradas. A estratégia descrita abaixo parece correta ou pode ser melhorada? A tabela base é chamada neede a tabela de histórico é chamadaneed_history

need
-- Armazena os dados de interesse
-- Tem um NOW()atribuído como parte created_dtsda INSERTconfiguração da tabela.
-- Tem um PER STATEMENTacionador after para obter a 'tabela de transição' de linhas excluídas.
-- O gatilho de instrução INSERTS INTO need_historypara preservar os dados.

need_history -- É quase um clone de necessidade, mas com alguns campos extras. Especificamente, deleted_dts, atribuído NOW()como padrão quando os dados são inseridos, e duration_secondsque armazena o número ~ de segundos que o registro existiu na tabela de necessidade.
-- Como este é o PG 11.5, não há colunas geradas, então precisarei de um EACH ROWgatilho para calcular duration_seconds.

Mais curto:
need com um gatilho de exclusão de nível de instrução que envia para need_history.

need_history com um gatilho de nível de linha para calcular duration_seconds, pois não tenho colunas geradas disponíveis no PG 11.x.

E, para responder à pergunta óbvia, não, não preciso armazenar o duration_secondsvalor derivado, pois ele pode ser gerado dinamicamente, mas, neste caso, quero desnormalizar para simplificar uma variedade de consultas, classificações e resumos .

Meu cérebro também está dizendo "pergunte sobre fatores de preenchimento ", e não sei por quê.

Abaixo está o código de configuração inicial, caso o resumo acima não esteja claro. Eu não enviei nenhum dado por isso ainda, então pode ter falhas.

Eu ficaria grato por qualquer conselho ou recomendação sobre a melhor forma de fazer isso no Postgres.

BEGIN;

DROP TABLE IF EXISTS data.need CASCADE;

CREATE TABLE IF NOT EXISTS data.need (
    id uuid NOT NULL DEFAULT NULL,
    item_id uuid NOT NULL DEFAULT NULL,
    facility_id uuid NOT NULL DEFAULT NULL,
    hsys_id uuid NOT NULL DEFAULT NULL,
    total_qty integer NOT NULL DEFAULT 0,
    available_qty integer NOT NULL DEFAULT 0,
    sterile_qty integer NOT NULL DEFAULT 0,
    still_need_qty integer NOT NULL DEFAULT 0,
    perc_down double precision NOT NULL DEFAULT '0',
    usage_ integer NOT NULL DEFAULT 0,
    need_for_case citext NOT NULL DEFAULT NULL,
    status citext NOT NULL DEFAULT NULL,
    created_dts timestamptz NOT NULL DEFAULT NOW(),

CONSTRAINT need_id_pkey
    PRIMARY KEY (id)
);


ALTER TABLE data.need OWNER TO user_change_structure;

COMMIT;

/* Define the trigger function to copy the deleted rows to the history table. */
CREATE FUNCTION data.need_delete_copy_to_history()  
  RETURNS trigger AS
$BODY$
BEGIN
        /* need.deleted_dts      is auto-assigned on INSERT over in need, and 
           need.duration_seconds is calculated in an INSERT trigger (PG 11.5, not PG 12, no generated columns). */

   INSERT INTO data.need_history 
            (id,
            item_id,
            facility_id,
            hsys_id,
            total_qty,
            available_qty,
            sterile_qty,
            still_need_qty,
            perc_down,
            usage_,
            need_for_case,
            status,
            created_dts)

     SELECT id,
            item_id,
            facility_id,
            hsys_id,
            total_qty,
            available_qty,
            sterile_qty,
            still_need_qty,
            perc_down,
            usage_,
            need_for_case,
            status,
            created_dts

       FROM deleted_rows;

    RETURN NULL; -- result is ignored since this is an AFTER trigger       
END;
$BODY$
LANGUAGE plpgsql;

 /* Bind a trigger event to the function. */
DROP TRIGGER IF EXISTS trigger_need_after_delete ON data.need;
CREATE TRIGGER trigger_need_after_delete 
    AFTER DELETE ON data.need
    REFERENCING OLD TABLE AS deleted_rows
    FOR EACH STATEMENT EXECUTE FUNCTION data.need_delete_copy_to_history();

/* Define the table. */
BEGIN;

DROP TABLE IF EXISTS data.need_history CASCADE;

CREATE TABLE IF NOT EXISTS data.need_history (
    id uuid NOT NULL DEFAULT NULL,
    item_id uuid NOT NULL DEFAULT NULL,
    facility_id uuid NOT NULL DEFAULT NULL,
    hsys_id uuid NOT NULL DEFAULT NULL,
    total_qty integer NOT NULL DEFAULT 0,
    available_qty integer NOT NULL DEFAULT 0,
    sterile_qty integer NOT NULL DEFAULT 0,
    still_need_qty integer NOT NULL DEFAULT 0,
    perc_down double precision NOT NULL DEFAULT '0',
    usage_ integer NOT NULL DEFAULT 0,
    need_for_case citext NOT NULL DEFAULT NULL,
    status citext NOT NULL DEFAULT NULL,
    created_dts timestamptz NOT NULL DEFAULT NULL,
    deleted_dts timestamptz NOT NULL DEFAULT NOW(),
    duration_seconds int4 NOT NULL DEFAULT 0,

CONSTRAINT need_history_id_pkey
    PRIMARY KEY (id)
);


ALTER TABLE data.need_history OWNER TO user_change_structure;

COMMIT;

/* Define the trigger function to update the duration count.
  In PG 12 we'll be able to do this with a generated column...easier. */

CREATE OR REPLACE FUNCTION data.need_history_insert_trigger() 
  RETURNS trigger AS
$BODY$
BEGIN
/* Use DATE_TRUNC seconds to get just the whole seconds part of the timestamps. */
NEW.duration_seconds =
      EXTRACT(EPOCH FROM (
        DATE_TRUNC('second', NEW.deleted_dts) - 
        DATE_TRUNC('second', NEW.created_dts)
        ));
  RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;


/* Bind a trigger event to the function. */
DROP TRIGGER IF EXISTS trigger_need_history_before_insert ON data.need_history;
CREATE TRIGGER trigger_need_history_before_insert 
    BEFORE INSERT ON data.need_history
    FOR EACH ROW EXECUTE FUNCTION data.need_history_insert_trigger();```
postgresql trigger
  • 2 2 respostas
  • 207 Views

2 respostas

  • Voted
  1. Best Answer
    Laurenz Albe
    2019-11-22T23:56:55+08:002019-11-22T23:56:55+08:00

    Isso parece bom.

    A parte difícil de implementar uma fila em SQL não é a historização, mas como gerenciar a própria fila (adicionar, localizar e remover itens). Se houver muito tráfego, você provavelmente precisará de configurações agressivas de autovacuum para a tabela de filas.

    Eu particionaria a tabela de histórico. O que as pessoas geralmente esquecem de projetar é como se livrar de dados antigos. A tabela de histórico pode ficar grande e você não precisará dos dados indefinidamente. Se você particionou a tabela (de modo que haja entre 10 e algumas centenas de partições), será fácil se livrar dos dados antigos.

    • 1
  2. jjanes
    2019-11-23T08:45:16+08:002019-11-23T08:45:16+08:00

    Não vejo nada de errado nisso. Como diz Laurenz, você deve considerar desde o início como irá excluir da tabela de histórico quando chegar a hora.

    "perguntar sobre fatores de preenchimento"

    O fator de preenchimento informa às operações INSERT ou COPY para deixar espaço suficiente em cada bloco para que UPDATE possa encaixar as novas versões de linhas no mesmo bloco da versão antiga. Você não descreve nenhuma operação UPDATE e as operações DELETE não exigem nenhum espaço adicional no bloco (elas atualizam as linhas no local para marcá-las como excluídas). Portanto, não há necessidades especiais aqui para definir o fator de preenchimento na mesa.

    • 1

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve