Eu tenho uma tabela PostgreSQL. select *
é muito lento enquanto select id
é bom e rápido. Acho que pode ser que o tamanho da linha seja muito grande e esteja demorando para transportar, ou pode ser algum outro fator.
Eu preciso de todos os campos (ou quase todos eles), então selecionar apenas um subconjunto não é uma solução rápida. A seleção dos campos que desejo ainda é lenta.
Aqui está meu esquema de tabela menos os nomes:
integer | not null default nextval('core_page_id_seq'::regclass)
character varying(255) | not null
character varying(64) | not null
text | default '{}'::text
character varying(255) |
integer | not null default 0
text | default '{}'::text
text |
timestamp with time zone |
integer |
timestamp with time zone |
integer |
O tamanho do campo de texto pode ser de qualquer tamanho. Mas ainda assim, não mais do que alguns kilobytes na pior das hipóteses.
Perguntas
- Existe algo sobre isso que grita 'louco ineficiente'?
- Existe uma maneira de medir o tamanho da página na linha de comando do Postgres para me ajudar a depurar isso?
Q2:
way to measure page size
O PostgreSQL fornece várias funções de tamanho de objeto de banco de dados . Empacotei os mais interessantes nesta consulta e adicionei algumas funções de acesso a estatísticas na parte inferior. (O módulo adicional pgstattuple ainda fornece funções mais úteis.)
Isso vai mostrar que diferentes métodos para medir o "tamanho de uma linha" levam a resultados muito diferentes. Tudo depende do que você quer medir, exatamente.
Esta consulta requer o Postgres 9.3 ou posterior . Para versões mais antigas, veja abaixo.
Usando uma
VALUES
expressão em umaLATERAL
subconsulta , para evitar soletrar cálculos para cada linha.Substitua
public.tbl
por seu nome de tabela opcionalmente qualificado pelo esquema para obter uma visualização compacta das estatísticas de tamanho de linha coletadas. Você pode envolver isso em uma função plpgsql para uso repetido, entregar o nome da tabela como parâmetro e usarEXECUTE
...Resultado:
Para versões mais antigas ( Postgres 9.2 ou anterior ):
Mesmo resultado.
Q1:
anything inefficient?
Você pode otimizar a ordem das colunas para economizar alguns bytes por linha, atualmente desperdiçados no preenchimento de alinhamento:
Isso economiza entre 8 e 18 bytes por linha. Eu chamo de Coluna Tetris . Ver:
Considere também:
Uma aproximação do tamanho de uma linha, incluindo o conteúdo do TOAST 'ed, é fácil de obter consultando o comprimento da representação TEXT de toda a linha:
Esta é uma aproximação do número de bytes que serão recuperados do lado do cliente durante a execução:
...assumindo que o chamador da consulta está solicitando resultados em formato de texto, que é o que a maioria dos programas faz (o formato binário é possível, mas não vale a pena na maioria dos casos).
A mesma técnica pode ser aplicada para localizar as
N
linhas "maiores no texto" detablename
:Existem algumas coisas que podem estar acontecendo. Em geral, duvido que o comprimento seja o problema proximal. Suspeito que, em vez disso, você tenha um problema relacionado ao comprimento.
Você diz que os campos de texto podem chegar a alguns k. Uma linha não pode ultrapassar 8k no armazenamento principal e é provável que seus campos de texto maiores tenham sido torrados ou movidos do armazenamento principal para um armazenamento estendido em arquivos separados. Isso torna seu armazenamento principal mais rápido (portanto, select id é realmente mais rápido porque menos páginas de disco para acessar), mas select * torna-se mais lento porque há mais E/S aleatória.
Se os tamanhos totais de linha ainda estiverem bem abaixo de 8k, você pode tentar alterar as configurações de armazenamento. Eu, no entanto, aviso que você pode fazer coisas ruins acontecerem ao inserir um atributo superdimensionado no armazenamento principal, então é melhor não tocar nisso se você não precisar e, se precisar, defina limites apropriados por meio de restrições de verificação. Portanto, o transporte provavelmente não é a única coisa. Pode estar agrupando muitos campos que exigem leituras aleatórias. Grandes números de leituras aleatórias também podem causar faltas de cache, e grandes quantidades de memória necessárias podem exigir que as coisas sejam materializadas em disco e um grande número de linhas largas, se uma junção estiver presente (e houver uma se o TOAST estiver envolvido) pode exigir mais custos juntar padrões, etc.
A primeira coisa que eu faria é selecionar menos linhas e ver se isso ajuda. Se isso funcionar, você pode tentar adicionar mais RAM ao servidor também, mas eu começaria e veria onde o desempenho começa a cair devido a alterações de plano e falhas de cache primeiro.
Usando as funções de tamanho de objeto de banco de dados mencionadas acima:
Se uma média do tamanho das linhas atuais for desejada, você poderá usar
pg_column_size
:Usando por coluna: