2014-10-31 14 views
5

Tworzę tabelę z 43kk rzędami, zapełniam je wartościami 1..200. Tak więc ~ 220 000 na każdą liczbę rozłożoną w tabeli.PostgreSQL Bitmap Skanowanie sterty na indeksie jest bardzo powolne, ale skanowanie tylko indeksu jest szybkie

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; 

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

Spodziewam całkowity czas < 1s, jest to możliwe? Mam dysk SSD, rdzeń i5 (1,8), 4 GB pamięci RAM. 9,3 Postgres.

Jeśli używam Index skanować tylko działa bardzo szybko:

explain analyze select val from foo where val = 55; 

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

Ale muszę zaznaczyć id nie val tak Incex Tylko skanowanie nie jest odpowiednie w moim przypadku.

Z góry dziękuję!

Dodatkowe informacje:

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

Wynik:

"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

Czy możesz dołączyć wynik tego zapytania do pytania: 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

Proszę, wykonaj "WYJAŚNIJ (analizuj, buforuj)" dla obu zapytań. I uwzględnij dane wyjściowe tego zapytania: 'SELECT nazwa, ustawienie, jednostka FROM pg_settings gdzie źródło NIE (" default "," override ") UNION ALL SELECT 'version', version(), NULL;' – vyegorov

Odpowiedz

6

Mam odpowiedź tutaj: http://ask.use-the-index-luke.com/questions/235/postgresql-bitmap-heap-scan-on-index-is-very-slow-but-index-only-scan-is-fast

Sztuką jest wykorzystanie Composite Index dla id i wartości:

create index val_id_index on foo(val, id); 

Więc Index Tylko skanowanie zostaną wykorzystane, ale mogę wybrać id teraz.

select id from foo where val = 55; 

Wynik:

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

Ale to działa tylko w PostgreSQL w wersji 9.2+. Jeśli zmusiłeś do korzystania z wersji poniżej, wypróbuj inne opcje.

0

Można spróbować zmniejszyć random_page_cost - dla SSD może być 1. Po drugie, może zwiększyć plik work_mem .. 10 MB to relatywnie niska wartość dla obecnych serwerów z gigabajtową pamięcią RAM. Powinieneś ponownie sprawdzić effect_cache_size - może być też zbyt niski.

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

Ustaw efektywny rozmiar_cache na 128mb i work_mem na 200mb i to nie pomogło, random_page_cost teraz 1. – user2138356

+1

możesz spróbować skomponować indeks. Możesz spróbować ukarać działanie wiersza, zwiększając cpu_tuple_cost. Musisz znaleźć kombinację work_mem, cpu_tuple_cost, random_page_cost, seq_page_cost, która działa dobrze dla twojego systemu. –

+0

jaki sugerujesz indeks komponowania? Odfiltrowuję tylko pojedyncze pole, więc złożony indeks jest nieobecny, nieprawdaż? – user2138356

2

Chociaż jesteś zapytań tylko 0,5% z tabeli, lub ~ 10MB warto danych (z prawie 2GB tabeli), wartości odsetek są rozłożone równomiernie na całej tabeli.

Widać to w pierwszym planie podasz:

  • BitmapIndexScan uzupełnia w 123.172ms
  • BitmapHeapScan trwa 17055.046ms.

Możesz spróbować grupować tabele w oparciu o kolejność indeksów, co spowoduje wstawienie wierszy na tych samych stronach. Na moich dyskach SATA mam następujące:

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 

Oczywiście, jest to operacja jednorazowa i będzie to się już nieco po bicie z upływem czasu.

Powiązane problemy