2014-10-31 12 views
5

Creo una tabella con righe da 43kk, le popola con i valori 1..200. Quindi ~ 220.000 per ogni numero diffuso attraverso il tavolo.Bitmap PostgreSQL La scansione dell'heap su indice è molto lenta ma la scansione solo indice è veloce

create table foo (id integer primary key, val bigint); 
insert into foo 
    select i, random() * 200 from generate_series(1, 43000000) as i; 
create index val_index on foo(val); 
vacuum analyze foo; 
explain analyze select id from foo where val = 55; 

Risultato: http://explain.depesz.com/s/fdsm

mi aspetto totale di runtime < 1s, è possibile? Ho SSD, core i5 (1,8), 4GB di RAM. 9,3 Postgres.

Se uso Indice solo la scansione funziona molto veloce:

explain analyze select val from foo where val = 55; 

http://explain.depesz.com/s/7hm

Ma ho bisogno di selezionare id non val così Incex Solo scansione non è adatto nel mio caso.

Grazie in anticipo!

Ulteriori informazioni:

SELECT relname, relpages, reltuples::numeric, pg_size_pretty(pg_table_size(oid)) 
FROM pg_class WHERE oid='foo'::regclass; 

Risultato:

"foo";236758;43800000;"1850 MB" 

Config:

"cpu_index_tuple_cost";"0.005";"" 
"cpu_operator_cost";"0.0025";"" 
"cpu_tuple_cost";"0.01";"" 
"effective_cache_size";"16384";"8kB" 
"max_connections";"100";"" 
"max_stack_depth";"2048";"kB" 
"random_page_cost";"4";"" 
"seq_page_cost";"1";"" 
"shared_buffers";"16384";"8kB" 
"temp_buffers";"1024";"8kB" 
"work_mem";"204800";"kB" 
+0

È possibile includere l'output di questa query nella domanda: 'SELECT relname, relpages, reltuples :: numeric, pg_size_pretty (pg_table_size (oid)) FROM pg_class WHERE oid = 'foo' :: regclass;' – vyegorov

+0

@vyegorov done ! – user2138356

+0

Si prega di fare 'ESPLORA (analizzare, buffer) 'per entrambe le query. Includere l'output di questa query: 'SELECT nome, impostazione, unità FROM pg_settings WHERE origine NOT IN ('default', 'override') UNION ALL SELECT 'versione', version(), NULL;' – vyegorov

risposta

6
risposta

ho ottenuto qui: http://ask.use-the-index-luke.com/questions/235/postgresql-bitmap-heap-scan-on-index-is-very-slow-but-index-only-scan-is-fast

Il trucco è quello di utilizzare indice composito per id e valore:

create index val_id_index on foo(val, id); 

Così Indice Solo scansione sarà utilizzato, ma posso selezionare id adesso.

select id from foo where val = 55; 

Risultato:

http://explain.depesz.com/s/nDt3

Ma questo funziona solo in Postgres con la versione 9.2+. Se si è obbligati a utilizzare le versioni di seguito, provare altre opzioni.

0

si può provare a ridurre random_page_cost - per SSD può essere 1. In secondo luogo, è può aumentare un work_mem .. 10 MB è un valore relativamente basso per i server attuali con gigabyte di RAM. Dovresti ricontrollare effective_cache_size - può anche essere troppo basso.

work_mem * max_connection * 2 + shared_buffers < RAM dedicated for Postgres 
effective_cache ~ shared_buffers + file system cache 
+0

Impostare effective_cache_size su 128mb e work_mem su 200mb e non ha aiutato, random_page_cost ora 1. – user2138356

+1

puoi provare a comporre indice. Puoi provare a penalizzare l'operazione di riga aumentando cpu_tuple_cost. Devi trovare una combinazione di work_mem, cpu_tuple_cost, random_page_cost, seq_page_cost che funziona bene per il tuo sistema. –

+0

quale indice di composizione stai suggerendo? Filtro solo per singolo campo, quindi l'indice composito non ha senso, non è vero? – user2138356

2

Anche se il gioco è l'interrogazione di solo lo 0,5% del tavolo, o ~ 10 MB vale la pena di dati (di quasi tabella 2 GB), i valori di interesse sono distribuiti in modo uniforme in tutta intera tabella.

Lo si può vedere nel primo piano che hai fornito:

  • BitmapIndexScan completa in 123.172ms
  • BitmapHeapScan prende 17055.046ms.

È possibile provare a raggruppare le tabelle in base all'ordine dell'indice, che raggrupperà le righe nelle stesse pagine. Sui miei dischi SATA Ho il seguente:

SET work_mem TO '300MB'; 
EXPLAIN (analyze,buffers) SELECT id FROM foo WHERE val = 55; 

    Bitmap Heap Scan on foo (...) (actual time=90.315..35091.665 rows=215022 loops=1) 
    Heap Blocks: exact=140489 
    Buffers: shared hit=20775 read=120306 written=24124 

SET maintenance_work_mem TO '1GB'; 
CLUSTER foo USING val_index; 
EXPLAIN (analyze,buffers) SELECT id FROM foo WHERE val = 55; 

    Bitmap Heap Scan on foo (...) (actual time=49.215..407.505 rows=215022 loops=1) 
    Heap Blocks: exact=1163 
    Buffers: shared read=1755 

Naturalmente, questa è un'operazione una tantum e si metterà a ottenere più bit per bit nel tempo.

Problemi correlati