2013-02-15 11 views
7

Oto powolne kwerendy na PostgreSQL 9.1.6, choć maksymalna liczba wynosi 2, z obu rzędach już zidentyfikowanych przez swoich kluczy podstawowych: (4,5 sekundy)W jaki sposób można zapobiec wpisywaniu podkwerendy w PostgreSQL?

EXPLAIN ANALYZE SELECT COUNT(*) FROM tbl WHERE id IN ('6d48fc431d21', 'd9e659e756ad') AND data ? 'building_floorspace' AND data ?| ARRAY['elec_mean_monthly_use', 'gas_mean_monthly_use']; 
                    QUERY PLAN                  
---------------------------------------------------------------------------------------------------------------------------------------------------- 
Aggregate (cost=4.09..4.09 rows=1 width=0) (actual time=4457.886..4457.887 rows=1 loops=1) 
    -> Index Scan using idx_tbl_on_data_gist on tbl (cost=0.00..4.09 rows=1 width=0) (actual time=4457.880..4457.880 rows=0 loops=1) 
     Index Cond: ((data ? 'building_floorspace'::text) AND (data ?| '{elec_mean_monthly_use,gas_mean_monthly_use}'::text[])) 
     Filter: ((id)::text = ANY ('{6d48fc431d21,d9e659e756ad}'::text[])) 
Total runtime: 4457.948 ms 
(5 rows) 

Hmm, może gdybym zrobić podkwerenda z tylko podstawowym elementem kluczowym pierwszy ...: (Nie, nadal 4.5+ sekund)

EXPLAIN ANALYZE SELECT COUNT(*) FROM ( SELECT * FROM tbl WHERE id IN ('6d48fc431d21', 'd9e659e756ad') ) AS t WHERE data ? 'building_floorspace' AND data ?| ARRAY['elec_mean_monthly_use', 'gas_mean_monthly_use']; 
                    QUERY PLAN                  
---------------------------------------------------------------------------------------------------------------------------------------------------- 
Aggregate (cost=4.09..4.09 rows=1 width=0) (actual time=4854.170..4854.171 rows=1 loops=1) 
    -> Index Scan using idx_tbl_on_data_gist on tbl (cost=0.00..4.09 rows=1 width=0) (actual time=4854.165..4854.165 rows=0 loops=1) 
     Index Cond: ((data ? 'building_floorspace'::text) AND (data ?| '{elec_mean_monthly_use,gas_mean_monthly_use}'::text[])) 
     Filter: ((id)::text = ANY ('{6d48fc431d21,d9e659e756ad}'::text[])) 
Total runtime: 4854.220 ms 
(5 rows) 

Jak mogę zapobiec Postgresa z inline podkwerendy?

Tło: Mam tabelę Postgres 9.1 z wykorzystaniem hstore i GiST index na jej temat.

+1

Szacowanie kosztów skanowania głównego indeksu wydaje się być całkiem błędne (na 4,09, jest niższe niż dostęp do indeksu klucza podstawowego). Możesz sprawdzić, czy możesz coś z tym zrobić, na przykład zapewnić nowe statystyki i/lub zwiększyć [cel statystyk] (http://www.postgresql.org/docs/9.1/static/runtime-config-query.html#GUC -DEFAULT-STATISTICS-CEL). –

+0

Zwiększyłem cel do 9999 i uruchomiłem "VACUUM ANALYZE" ... wciąż uzyskując ten sam kosztorys w porównaniu do rozbieżności w rzeczywistości. Dzięki za twoją sugestię! –

Odpowiedz

4

Najwyraźniej istnieje way to tell Postgres not to inline: (0.223ms!)

EXPLAIN ANALYZE SELECT COUNT(*) FROM ( SELECT * FROM tbl WHERE id IN ('6d48fc431d21', 'd9e659e756ad') OFFSET 0) AS t WHERE data ? 'building_floorspace' AND data ?| ARRAY['elec_mean_monthly_use', 'gas_mean_monthly_use']; 
                   QUERY PLAN                 
------------------------------------------------------------------------------------------------------------------------------------------ 
Aggregate (cost=8.14..8.15 rows=1 width=0) (actual time=0.165..0.166 rows=1 loops=1) 
    -> Subquery Scan on t (cost=4.14..8.14 rows=1 width=0) (actual time=0.160..0.160 rows=0 loops=1) 
     Filter: ((t.data ? 'building_floorspace'::text) AND (t.data ?| '{elec_mean_monthly_use,gas_mean_monthly_use}'::text[])) 
     -> Limit (cost=4.14..8.13 rows=2 width=496) (actual time=0.086..0.092 rows=2 loops=1) 
       -> Bitmap Heap Scan on tbl (cost=4.14..8.13 rows=2 width=496) (actual time=0.083..0.086 rows=2 loops=1) 
        Recheck Cond: ((id)::text = ANY ('{6d48fc431d21,d9e659e756ad}'::text[])) 
        -> Bitmap Index Scan on tbl_pkey (cost=0.00..4.14 rows=2 width=0) (actual time=0.068..0.068 rows=2 loops=1) 
          Index Cond: ((id)::text = ANY ('{6d48fc431d21,d9e659e756ad}'::text[])) 
Total runtime: 0.223 ms 
(9 rows) 

Sztuką jest OFFSET 0 w podzapytania.

+0

... ale PostgreSQL nie ma wskazówek dotyczących zapytań. Nie naprawdę. ;-) –

7

myślę OFFSET 0 jest lepszym rozwiązaniem, ponieważ jest to bardziej oczywiste hack pokazując, że coś dziwnego się dzieje, i to jest mało prawdopodobne, że kiedykolwiek zmienić zachowanie optymalizatora wokół OFFSET 0 ... ubezpieczeniowy nadzieją współczynniki CTE będzie inlineable w pewnym momencie . Poniższe wyjaśnienie dotyczy kompletności; użyj odpowiedzi Seamusa.

Dla nieskorelowanych podzapytaniami można wykorzystać odmowę PostgreSQL do inline WITH zapytania do rephrase zapytanie jako:

WITH t AS (
    SELECT * FROM tbl WHERE id IN ('6d48fc431d21', 'd9e659e756ad') 
) 
SELECT COUNT(*) 
FROM t 
WHERE data ? 'building_floorspace' 
AND data ?| ARRAY['elec_mean_monthly_use', 'gas_mean_monthly_use']; 

ma tyle ten sam efekt jak OFFSET 0 włamania i jak offset 0 Hack wyczynach dziwactwa w PG optymalizator, którego ludzie używają, aby ominąć wskazówki Pg dotyczące zapytań ... używając ich jako wskazówek dotyczących zapytań.

Powiązane problemy