Eu tenho uma tabela do PostgreSQL. select *
é muito lento select id
e agradável e rápido. Acho que o tamanho da linha é muito grande e está demorando para ser transportado, ou pode ser algum outro fator.
Eu preciso de todos os campos (ou quase todos), portanto, selecionar apenas um subconjunto não é uma solução rápida. A seleção dos campos que eu quero ainda é lenta.
Aqui está o 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 no pior caso.
Questões
- Existe algo sobre isso que grita "loucamente ineficiente"?
- Existe uma maneira de medir o tamanho da página na linha de comando do Postgres para me ajudar a depurar isso?
length(*)
e não apenaslength(field)
? Eu sei que chars não bytes, mas eu só preciso de um valor aproximado.Respostas:
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 fornece funções mais úteis ainda.)
Isso mostra que métodos diferentes para medir o "tamanho de uma linha" levam a resultados muito diferentes. Tudo depende exatamente do que você deseja medir.
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 a ortografia dos cálculos para cada linha.Substitua
public.tbl
(duas vezes) pelo nome da tabela opcionalmente qualificada para o esquema para obter uma visualização compacta das estatísticas coletadas sobre o tamanho de suas linhas. Você pode agrupar isso em uma função plpgsql para uso repetido, inserir 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 salvar alguns bytes por linha, atualmente desperdiçados no preenchimento do alinhamento:
Isso economiza entre 8 e 18 bytes por linha. Eu chamo de "coluna tetris" . Detalhes:
Considere também:
fonte
, unnest(val) / ct
por, (LEAST(unnest(val), unnest(val) * ct)) / (ct - 1 + sign(ct))
e não jogará. A justificativa é que, quandoct
for0
,val
será substituída por0
ect
será substituída por1
.É fácil obter uma aproximação do tamanho de uma linha, incluindo o conteúdo do TOAST , consultando o comprimento da representação TEXT de toda a linha:
Esta é uma aproximação aproximada ao número de bytes que serão recuperados no lado do cliente ao executar:
... supondo que o chamador da consulta solicite resultados em formato de texto, que é o que a maioria dos programas faz (o formato binário é possível, mas na maioria dos casos não vale a pena).
A mesma técnica pode ser aplicada para localizar as
N
linhas "maiores em texto" detablename
:fonte
Existem algumas coisas que podem estar acontecendo. Em geral, duvido que o comprimento seja o problema proximal. Suspeito que 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 TOASTADOS ou movidos do armazenamento principal para um armazenamento estendido em arquivos separados. Isso torna seu armazenamento principal mais rápido (portanto, o ID de seleção é realmente mais rápido porque há menos páginas em disco para acessar), mas a seleção * se torna mais lenta porque há mais E / S aleatória.
Se o tamanho total de sua linha ainda estiver bem abaixo de 8k, tente alterar as configurações de armazenamento. No entanto, eu alertaria que você pode obter coisas ruins ao inserir um atributo superdimensionado no armazenamento principal, para não tocar nisto se não for necessário e, se for o caso, defina limites apropriados por meio de restrições de verificação. Portanto, o transporte provavelmente não é a única coisa. Pode estar agrupando muitos, muitos campos que requerem leituras aleatórias. Um grande número de leituras aleatórias também pode causar falhas no cache, e uma grande quantidade de memória necessária pode exigir que as coisas se materializem no disco e um grande número de linhas largas, se houver uma junção (e houver uma se o TOAST estiver envolvido) pode exigir mais custos. juntar padrões etc.
A primeira coisa que gostaria de fazer é selecionar menos linhas e ver se isso ajuda. Se isso funcionar, você também pode tentar adicionar mais RAM ao servidor, mas eu começaria e veria onde o desempenho começa a cair devido a alterações no plano e falhas de cache primeiro.
fonte
Usando as funções de tamanho de objeto de banco de dados mencionadas acima:
fonte