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 / 167525
Accepted
Mad Scientist
Mad Scientist
Asked: 2017-03-19 10:15:42 +0800 CST2017-03-19 10:15:42 +0800 CST 2017-03-19 10:15:42 +0800 CST

Estatísticas inconsistentes na coluna jsonb com índice btree

  • 772

Percebi que o desempenho de uma consulta envolvendo uma coluna jsonb variou significativamente entre as execuções de VACUUM ANALYZE durante o teste. Eu recebo planos de execução completamente diferentes aparentemente aleatoriamente depois de analisar a tabela.

Estou usando o Postgres 9.6 aqui. A configuração para meus testes é a seguinte, estou inserindo uma única chave "x" na coluna jsonb "params" com valores entre 1 e 6, sendo 1 o valor mais raro e 6 o mais comum. Eu também tenho uma coluna int regular "single_param" que contém a mesma distribuição de valores para comparação.:

CREATE TABLE test_data (
    id      serial,
    single_param    int,
    params      jsonb
);

INSERT INTO test_data
SELECT 
    generate_series(1, 1000000) AS id, 
    floor(log(random() * 9999999 + 1)) AS single_param,
    json_build_object(
        'x', floor(log(random() * 9999999 + 1))
    ) AS params;

CREATE INDEX idx_test_btree ON test_data (cast(test_data.params->>'x' AS int));
CREATE INDEX idx_test_gin ON test_data USING GIN (params);
CREATE INDEX ON test_data(id)
CREATE INDEX ON test_data(single_param)

A consulta que estou testando é uma consulta típica para paginar resultados, estou classificando por id e limitando a saída às primeiras 50 linhas.

SELECT * FROM test_data where (params->>'x')::int = 1 ORDER BY id DESC LIMIT 50;

Eu recebo uma das duas saídas de análise de explicação aleatoriamente após a execução VACUUM ANALYZE:

Limit  (cost=0.42..836.59 rows=50 width=33) (actual time=39.679..410.292 rows=10 loops=1)
  ->  Index Scan Backward using test_data_id_idx on test_data  (cost=0.42..44317.43 rows=2650 width=33) (actual time=39.678..410.283 rows=10 loops=1)
        Filter: (((params ->> 'x'::text))::integer = 1)
        Rows Removed by Filter: 999990"
Planning time: 0.106 ms
Execution time: 410.314 ms

ou

Limit  (cost=8.45..8.46 rows=1 width=33) (actual time=0.032..0.034 rows=10 loops=1)
  ->  Sort  (cost=8.45..8.46 rows=1 width=33) (actual time=0.032..0.032 rows=10 loops=1)
        Sort Key: id DESC
        Sort Method: quicksort  Memory: 25kB
        ->  Index Scan using idx_test_btree on test_data  (cost=0.42..8.44 rows=1 width=33) (actual time=0.007..0.016 rows=10 loops=1)
              Index Cond: (((params ->> 'x'::text))::integer = 1)
Planning time: 0.320 ms
Execution time: 0.052 ms

A diferença é que a estimativa para o número de colunas correspondentes à cláusula where é diferente entre os dois planos. Na primeira a estimativa é de 2650 linhas, na segunda 1 linha enquanto o número real é de 10 linhas.

A seguinte versão da consulta que pode potencialmente usar o índice GIN parece usar uma estimativa padrão para a coluna json de 1%, o que também resulta no plano de consulta incorreto como acima:

SELECT * FROM test_data where params @> '{"x": 1}' ORDER BY id DESC LIMIT 50;

Minha suposição original era que o Postgres não teria nenhuma estatística na coluna jsonb e sempre usaria uma estimativa como faz para a consulta usando o @>operador. Mas para a consulta que é escrita poder usar o índice btree que criei, ela usa estimativas diferentes. Às vezes, esses são bons o suficiente, e às vezes são ruins.

De onde vêm essas estimativas? Eu acho que eles são algum tipo de estatística que o Postgres cria com o índice. Para estatísticas de coluna existe a opção de coletar estatísticas mais precisas, existe algo assim para essas estatísticas aqui? Ou alguma outra maneira de fazer com que o Postgres escolha o melhor plano no meu caso?

postgresql index-tuning
  • 1 1 respostas
  • 1965 Views

1 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2017-03-21T08:22:50+08:002017-03-21T08:22:50+08:00

    Atualmente (versão 9.6), o Postgres não possui estatísticas sobre os componentes internos de tipos de documentos como json, jsonb, xmlou hstore. (Tem havido discussão se e como mudar isso.) Em vez disso, o planejador de consultas do Postgres usa estimativas de frequência padrão constantes (como você observou).

    No entanto , existem estatísticas separadas para índices funcionais como o seu idx_test_btree. O manual tem essa dica para você:

    Dica: Embora o ajuste de ANALYZEfrequência por coluna possa não ser muito produtivo, talvez valha a pena fazer o ajuste por coluna do nível de detalhe das estatísticas coletadas pelo ANALYZE. Colunas que são muito usadas em WHEREcláusulas e têm distribuições de dados altamente irregulares podem exigir um histograma de dados de granulação mais fina do que outras colunas. Consulte ALTER TABLE SET STATISTICSou altere o padrão de todo o banco de dados usando o parâmetro de configuração default_statistics_target.

    Além disso, por padrão, há informações limitadas disponíveis sobre a seletividade das funções. No entanto, se você criar um índice de expressão que usa uma chamada de função, estatísticas úteis serão coletadas sobre a função, o que pode melhorar muito os planos de consulta que usam o índice de expressão.

    O volume de estatísticas coletadas depende da configuração geral de default_statistics_target, que pode ser anulada com uma configuração por coluna. A configuração da coluna cobre automaticamente os índices dependentes.

    A configuração padrão de 100é conservadora. Para seu teste com 1 milhão de linhas, se a distribuição de dados for desigual, pode ajudar a aumentá-la substancialmente. Verificando isso mais uma vez, descobri que você pode realmente ajustar o destino das estatísticas por coluna de índice com ALTER INDEX, que atualmente não está documentado. Veja a discussão relacionada em pgsql-docs.

    ALTER TABLE idx_test_btree ALTER int4 SET STATISTICS 2000;  -- max 10000, default 100
    

    Os nomes padrão para colunas de índice não são exatamente intuitivos, mas você pode procurá-los com:

    SELECT attname FROM pg_attribute WHERE attrelid = 'idx_test_btree'::regclass
    

    Deve resultar no nome do tipo int4como nome da coluna de índice para o seu caso.

    A melhor configuração para STATISTICSdepende de vários fatores: distribuição de dados, tipo de dados, frequência de atualização, características de consultas típicas, ...

    Internamente, isso define o valor de pg_attribute.attstattarget, e o significado exato disso é ( por documentação ):

    Para tipos de dados escalares, attstattargeté o número de destino de "valores mais comuns" a serem coletados e o número de destino de compartimentos de histograma a serem criados.

    Em seguida, execute ANALYZEse você não quiser esperar o autovacuum entrar em ação:

    ANALYZE test_data;
    

    Você deveANALYZE a tabela, pois não pode ANALYZEindexar diretamente. Verifique com (antes e depois se quiser verificar o efeito):

    SELECT * FROM pg_statistic WHERE starelid = 'idx_test_btree'::regclass;
    

    Tente sua consulta novamente...

    Relacionado:

    • Verificar alvos de estatísticas no PostgreSQL
    • Índice que não é usado, mas influencia a consulta
    • Índice parcial do PostgreSQL não utilizado quando criado em uma tabela com dados existentes
    • 7

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