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 / 66292
Accepted
Jack Douglas
Jack Douglas
Asked: 2014-05-31 13:45:13 +0800 CST2014-05-31 13:45:13 +0800 CST 2014-05-31 13:45:13 +0800 CST

Como posso obter o agrupamento de linhas sem o bloqueio exclusivo e a sobrecarga de registro do comando `cluster`?

  • 772

O CLUSTERcomando em uma tabela grande pode levar muito tempo e bloqueia leituras e gravações na tabela durante sua execução.

Não preciso que os dados em minha tabela sejam estritamente classificados em ordem de índice, só quero que as linhas que são comumente consultadas juntas tenham mais probabilidade de estar nos mesmos blocos de banco de dados do que espalhadas uniformemente pela tabela (que é a distribuição que eles naturalmente devido à natureza da forma como a data é inserida na tabela).

Isso pode fazer uma grande diferença. No exemplo abaixo, a única diferença é que o insertpossui um adicional order by mod(g,10)para que os dados de teste sejam pré-agrupados por host_id. Muito menos blocos precisam ser lidos ao obter todos os dados para um arquivo host_id.

Existe alguma maneira de obter esse tipo de agrupamento sem o bloqueio exclusivo e a sobrecarga de registro do clustercomando?

create schema stack;
set search_path=stack;
--
create table foo(host_id integer, bar text default repeat('a',400));
insert into foo(host_id) select mod(g,10) from generate_series(1,500000) g;
create index nu_foo on foo(host_id);
explain analyze select count(bar) from foo where host_id=1;
/*
                                                            QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=30188.66..30188.67 rows=1 width=404) (actual time=1129.858..1129.859 rows=1 loops=1)
   ->  Bitmap Heap Scan on foo  (cost=919.27..30066.46 rows=48883 width=404) (actual time=253.149..1110.013 rows=50000 loops=1)
         Recheck Cond: (host_id = 1)
         Rows Removed by Index Recheck: 320257
         ->  Bitmap Index Scan on nu_foo  (cost=0.00..907.04 rows=48883 width=0) (actual time=251.863..251.863 rows=50000 loops=1)
               Index Cond: (host_id = 1)
 Total runtime: 1129.893 ms
*/
--
drop table foo;
--
create table foo(host_id integer, bar text default repeat('a',400));
insert into foo(host_id) select mod(g,10) from generate_series(1,500000) g order by mod(g,10);
create index nu_foo on foo(host_id);
explain analyze select count(bar) from foo where host_id=1;
/*
                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=7550.20..7550.21 rows=1 width=32) (actual time=24.397..24.397 rows=1 loops=1)
   ->  Bitmap Heap Scan on foo  (cost=47.80..7543.95 rows=2500 width=32) (actual time=3.988..16.189 rows=50000 loops=1)
         Recheck Cond: (host_id = 1)
         ->  Bitmap Index Scan on nu_foo  (cost=0.00..47.17 rows=2500 width=0) (actual time=3.649..3.649 rows=50000 loops=1)
               Index Cond: (host_id = 1)
 Total runtime: 24.437 ms
*/
--
drop schema stack cascade;
postgresql clustering
  • 1 1 respostas
  • 1050 Views

1 respostas

  • Voted
  1. Best Answer
    Jack Douglas
    2014-05-31T13:45:13+08:002014-05-31T13:45:13+08:00

    Você pode fazer isso sem usar o clustercomando e ter a tabela bloqueada ou gerar WAL para a tabela inteira. O custo é que você precisa verificar a tabela regularmente.

    A ideia básica é:

    1. desligue o aspirador automático da mesa
    2. verifique cada bloco para determinar o grau de agrupamento
    3. exclua e insira novamente todas as linhas de blocos abaixo de um limite de agrupamento
    4. aspirar manualmente para liberar esses blocos (completos)
    5. repita os passos 2-4 tão regularmente quanto necessário

    dados de amostra do esquema de teste inicialmente 'parte-agrupados':

    create schema stack;
    set search_path=stack;
    create type t_tid as (blkno bigint, rowno integer);
    create table foo(host_id integer, bar text default repeat('a',400)) with (autovacuum_enabled=false);
    insert into foo(host_id) select mod(g,10) from generate_series(1,500000) g order by mod(g,10);
    insert into foo(host_id) select mod(g,10) from generate_series(1,500000) g;
    create index nu_foo on foo(host_id);
    

    estatísticas iniciais de agrupamento:

    select cn, count(*)
    from ( select count(*) cn
           from (select distinct (ctid::text::t_tid).blkno, host_id from foo) z
           group by blkno ) z
    group by cn
    order by cn;
    /*
     cn | count
    ----+-------
      1 | 27769  <---- half clustered
      2 |     8
      5 |     1
     10 | 27778  <---- half un-clustered
    */
    select count(distinct (ctid::text::t_tid).blkno) from foo where host_id=1;
    /*
     count
    -------
     30558  <--------- lots of blocks to read for `host_id=1`
    */
    

    análise inicial ( 2146,503 ms ):

    explain analyze select count(bar) from foo where host_id=1;
    /*
                                                               QUERY PLAN
    --------------------------------------------------------------------------------------------------------------------------------
     Aggregate  (cost=15097.30..15097.31 rows=1 width=32) (actual time=2146.157..2146.158 rows=1 loops=1)
       ->  Bitmap Heap Scan on foo  (cost=95.17..15084.80 rows=5000 width=32) (actual time=21.586..2092.379 rows=100000 loops=1)
             Recheck Cond: (host_id = 1)
             Rows Removed by Index Recheck: 286610
             ->  Bitmap Index Scan on nu_foo  (cost=0.00..93.92 rows=5000 width=0) (actual time=19.232..19.232 rows=100000 loops=1)
                   Index Cond: (host_id = 1)
     Total runtime: 2146.503 ms
    */
    

    exclua e insira novamente as linhas não agrupadas:

    with w as ( select blkno
                from (select distinct (ctid::text::t_tid).blkno, host_id from foo) z
                group by blkno
                having count(*)>2 )
       , d as ( delete from foo
                where (ctid::text::t_tid).blkno in (select blkno from w)
                returning * )
    insert into foo(host_id,bar) select host_id,bar from d order by host_id;
    --
    vacuum foo;
    

    novas estatísticas de agrupamento:

    select cn, count(*)
    from ( select count(*) cn
           from (select distinct (ctid::text::t_tid).blkno, host_id from foo) z
           group by blkno ) z
    group by cn
    order by cn;
    /*
     cn | count
    ----+-------
      1 | 55541  <---- fully clustered
      2 |    16
    */
    select count(distinct (ctid::text::t_tid).blkno) from foo where host_id=1;
    /*
     count
    -------
      5558  <--------- far fewer blocks to read for `host_id=1`
    */
    

    nova análise ( 48,804 ms ):

    explain analyze select count(bar) from foo where host_id=1;
    /*
                                                              QUERY PLAN
    -------------------------------------------------------------------------------------------------------------------------------
     Aggregate  (cost=16110.64..16110.65 rows=1 width=32) (actual time=48.760..48.761 rows=1 loops=1)
       ->  Bitmap Heap Scan on foo  (cost=131.18..16098.14 rows=5000 width=32) (actual time=8.402..32.439 rows=100000 loops=1)
             Recheck Cond: (host_id = 1)
             ->  Bitmap Index Scan on nu_foo  (cost=0.00..129.93 rows=5000 width=0) (actual time=7.636..7.636 rows=100000 loops=1)
                   Index Cond: (host_id = 1)
     Total runtime: 48.804 ms
    */
    

    limpar:

    drop schema stack cascade;
    

    O acima é viável agora, mas é um pouco peculiar (precisa desligar o auto-vácuo para a mesa) e requer varredura completa regular da mesa. Acho que algo semelhante sem as desvantagens poderia ser incorporado ao postgres. Você precisaria de:

    1. Um índice com eficiência de espaço para agrupar (isso está chegando em 9.4 com compactação GIN, ou melhor ainda em 9.5 com o novo tipo de índice BRIN)
    2. Um processo 'semelhante a vácuo' que examinaria esse índice para detectar quais blocos precisam ser excluídos/reinserido (o ideal seria reinserir as linhas em novos blocos para que o vácuo automático possa ser deixado como padrão)
    • 5

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