Em 28 de julho de 2010 15:33, Monica Ferrari Villarino
<[email protected]> escreveu:
> Será que é possível otimizar a seguinte consulta, executada de hora em hora
> no banco:
>
> select count(*) from history;
>
> Essa consulta costuma ter uma duração que varia de  32000.000 ms a 62262.751
> ms  conforme o horário em que é executada.
>
> A tabela history possui em média 87 milhões de registros.
>
> É uma tabela que sofre muito insert/update/delete.
>
> (corte)
>

Já precisei de algo parecido em mais de uma tabela (auditoria), e para
reduzir ao máximo os problemas de desempenho foi criada uma tabela de
contadores que é atualizada a cada operação.

Adaptei o script para a sua tabela, espero que possa ajudá-la.

-- INÍCIO DO SCRIPT
-- ***************************
-- PARA A COLUNA counter_type:
-- ***************************
-- 'ROW' = Número de Linhas, 'DEL' = Delete, 'UPD' = Update, 'INS' = Insert
CREATE TABLE table_counter (
        table_name VARCHAR(100) not null,
        counter_type CHAR(3) not null,
        counter_value INTEGER not null default 0
);
--
ALTER TABLE table_counter ADD PRIMARY KEY( table_name, counter_type );
--
-- Adiciona pela primeira vez o total de registros na tabela
--
INSERT INTO table_counter( table_name, counter_type, counter_value )
                VALUES( 'history', 'ROW', ( SELECT COUNT(*) FROM history ) );
--
CREATE FUNCTION trf_ins_history_count()
RETURNS TRIGGER AS
$BODY$
DECLARE
        _RS RECORD;
        i_count INTEGER;
BEGIN
        SELECT INTO _RS counter_value FROM table_counter WHERE table_name =
'history' AND counter_type = 'INS';

        IF NOT FOUND THEN
                INSERT INTO table_counter( table_name, counter_type, 
counter_value )
VALUES( 'history', 'INS', 0 );
                i_count := 1;
        ELSE
                i_count := _RS.counter_value;
                i_count := i_count + 1;
        END IF;

        -- Atualiza a quantidade de INSERTs que a tabela recebeu
        UPDATE table_counter SET counter_value = i_count WHERE table_name =
'history' AND counter_type = 'INS';
        
        -- Atualiza o número de registros
        -- Deve existir um TRIGGER para DELETE que remova uma unidade a cada
registro eliminado.
        UPDATE table_counter SET counter_value = counter_value +1 WHERE
table_name = 'history' AND counter_type = 'ROW';

        RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
--
CREATE TRIGGER tr_ins_history AFTER INSERT ON history FOR EACH ROW
EXECUTE PROCEDURE trf_ins_history_count();
--
CREATE FUNCTION trf_upd_history_count()
RETURNS TRIGGER AS
$BODY$
DECLARE
        _RS RECORD;
        i_count INTEGER;
BEGIN
        SELECT INTO _RS counter_value FROM table_counter WHERE table_name =
'history' AND counter_type = 'UPD';

        IF NOT FOUND THEN
                INSERT INTO table_counter( table_name, counter_type, 
counter_value )
VALUES( 'history', 'UPD', 0 );
                i_count := 1;
        ELSE
                i_count := _RS.counter_value;
                i_count := i_count + 1;
        END IF;

        -- Atualiza a quantidade de UPDATES que a tabela recebeu
        UPDATE table_counter SET counter_value = i_count WHERE table_name =
'history' AND counter_type = 'UPD';
        
        -- NÃO Atualiza o número de registros
        
        RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
--
CREATE TRIGGER tr_upd_history AFTER UPDATE ON history FOR EACH ROW
EXECUTE PROCEDURE trf_upd_history_count();
--
CREATE FUNCTION trf_del_history_count()
RETURNS TRIGGER AS
$BODY$
DECLARE
        _RS RECORD;
        i_count INTEGER;
BEGIN
        SELECT INTO _RS counter_value FROM table_counter WHERE table_name =
'history' AND counter_type = 'DEL';

        IF NOT FOUND THEN
                INSERT INTO table_counter( table_name, counter_type, 
counter_value )
VALUES( 'history', 'DEL', 0 );
                i_count := 1;
        ELSE
                i_count := _RS.counter_value;
                i_count := i_count + 1;
        END IF;

        -- Atualiza a quantidade de INSERTs que a tabela recebeu
        UPDATE table_counter SET counter_value = i_count WHERE table_name =
'history' AND counter_type = 'DEL';
        
        -- Atualiza o número de registros
        UPDATE table_counter SET counter_value = counter_value -1 WHERE
table_name = 'history' AND counter_type = 'ROW';

        RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
--
CREATE TRIGGER tr_del_history AFTER DELETE ON history FOR EACH ROW
EXECUTE PROCEDURE trf_del_history_count();
-- FIM DO SCRIPT




-- 
TIAGO J. ADAMI
http://www.adamiworks.com
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a