PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Esses malditos objetos grandes

Introdução


O PostgreSQL dá aos desenvolvedores a chance de escolher entre dois recursos de armazenamento possíveis para grandes dados binários:Bytea e LargeObjects.

Objetos grandes existem há muito tempo, e o PostgreSQL tem uma maneira inteligente de armazenar grandes dados binários. Ele faz isso dividindo-o em pedaços de LOBLKSIZE (um quarto de BLCKSZ). Dessa forma, as tuplas de pg_largeobject não são derramadas na mesa de torradas.

Por outro lado, bytea armazena os dados binários diretamente na tupla, o que pode levar a um desempenho ruim dependendo da aparência do seu esquema.

Isso parece ótimo se você tiver uma interface inteligente para lidar com a manipulação desses arquivos binários, especialmente se a atualização modificar apenas uma pequena parte de todo o arquivo binário.

Mas normalmente não nos preocupamos em escrever código que tire vantagem disso e, em vez disso, escrevemos novamente todos os dados binários.

Uma das coisas que acredito fazer com que as pessoas adotem objetos grandes são as funções disponíveis para importar e exportar arquivos diretamente do servidor de banco de dados para seu sistema de arquivos. Há um contra nisso:se o aplicativo estiver em um servidor diferente, você precisará de mais código para mover o arquivo para o local onde é necessário.

Um problema que você pode enfrentar


Nos últimos dias tive que examinar um banco de dados usado para armazenar informações de sessões de usuários de um sistema Java CAS. Descobri que havia quase 100 milhões de objetos grandes no banco de dados, não muito grandes.

Examinei as tabelas de usuários verificando os campos que tinham um oid campo e, em seguida, faço referência cruzada dos valores nesses campos com o pg_largeobject_metadata tabela. Descobri que 96% desses objetos grandes eram órfãos. Esses são objetos grandes que não foram referenciados por nenhuma tupla das tabelas do usuário.

Investigações posteriores concluíram que o Hibernate não cuidou de limpar os objetos grandes que criou ao deletar ou atualizar tuplas com campos oid. Portanto, estava gerando uma grande quantidade de inchaço que não podia ser limpo por aspiração, mas precisava ser removido da tabela pg_largeobjects manualmente.

No caso particular do banco de dados CAS, esta consulta serviu para identificar os objetos grandes ainda em uso:
SELECT unnest(array[expiration_policy,
                    authentication,
                    services_granted_access_to])
       FROM public.ticketgrantingticket
UNION
SELECT unnest(array[expiration_policy, 
                    service])
       FROM public.serviceticket

A consulta pode ser usada para excluir da lista de objetos grandes quais remover. Algo assim:
SELECT lo_unlink(pg_largeobject_metadata.oid)
       FROM pg_largeobject_metadata
       WHERE pg_largeobject_metadata.oid NOT IN (
             SELECT unnest(array[expiration_policy,
                                 authentication,
                                 services_granted_access_to])
             FROM public.ticketgrantingticket
             UNION
             SELECT unnest(array[expiration_policy, 
                                 service])
             FROM public.serviceticket
)

Conclusão


Objetos grandes têm seus problemas, assim como outros tipos de dados (especialmente ao usar tipos para armazenar dados binários grandes). Cabe aos desenvolvedores e administradores de banco de dados aproveitar os prós e mitigar os contras.

Demos uma possível consulta para realizar a limpeza, mas também há uma boa extensão que limpa os objetos grandes órfãos com gatilhos:Large Object Manager

Algumas pessoas podem preferir executar uma consulta de limpeza durante as horas de silêncio em vez de executar um acionador a cada UPDATE e EXCLUIR . Em sistemas com UPDATE muito, muito baixo e/ou EXCLUIR taxa, um gatilho sobre cada tabela que tem um oid campo, parece uma solução mais elegante. E qualquer perda de desempenho por ter que executar a função de gatilho seria supérflua.

De qualquer forma, objetos grandes ainda têm grandes fãs, provavelmente por causa das funções internas fornecidas para importar e exportar os dados binários diretamente para o sistema de arquivos local. Com o bytea, você normalmente usaria mais memória na camada do aplicativo. É um procedimento muito comum ler o campo binário completamente em uma variável e depois processá-lo.

Eu poderia escrever algo sobre o uso do bytea que usei em um dos meus desenvolvimentos anteriores em um post futuro no blog.