2016-07-03 18 views
2

Warum bekomme ich Seq scan, wenn ich den Teilindex in \d+ Befehle sehen kann;Teilindizierung nicht wirksam

\d+ call_records; 

id     | integer      | not null default nextval('call_records_id_seq'::regclass) | plain |    | 

plain_crn   | bigint      | 
active    | boolean      | default true 
timestamp   | bigint      | default 0 


Indexes: 
    "index_call_records_on_plain_crn" UNIQUE, btree (plain_crn) 
    "index_call_records_on_active" btree (active) WHERE active = true 

Was id erwartet war ein Index Scan.

EXPLAIN select * from call_records where id=1; 
             QUERY PLAN          
---------------------------------------------------------------------------------------- 
Index Scan using call_records_pkey on call_records (cost=0.14..8.16 rows=1 width=373) 
    Index Cond: (id = 1) 
(2 rows) 

Das Gleiche gilt für plain_crn

EXPLAIN select * from call_records where plain_crn=1; 
               QUERY PLAN            
------------------------------------------------------------------------------------------------------ 
Index Scan using index_call_records_on_plain_crn on call_records (cost=0.14..8.16 rows=1 width=373) 
    Index Cond: (plain_crn = 1) 
(2 rows) 

Aber, es ist nicht das gleiche bei active.

EXPLAIN select * from call_records where active=true;                               QUERY PLAN       
----------------------------------------------------------------- 
Seq Scan on call_records (cost=0.00..12.00 rows=100 width=373) 
    Filter: active 
(2 rows) 
+1

Bitte senden Sie die Ausgabe von 'erklären (analysieren, ausführlich)' für alle Abfragen –

Antwort

3

Ob PostgreSQL den Index für "aktiv" verwendet, hängt vom Verhältnis von wahr zu falsch ab. An einem Punkt, an dem mehr als wahr ist, entscheidet der Abfrageplaner, dass der Tabellenscan wahrscheinlich schneller ist.

Ich habe eine Tabelle zum Testen erstellt und eine Million Zeilen mit zufälligen (ish) Daten geladen.

select active, count(*) 
from call_records 
group by active; 
 
active count 
-- 
f  499983 
t  500017 

Wahre und falsche haben in etwa die gleiche Anzahl von Zeilen. Hier ist der Ausführungsplan.

explain analyze 
select * from call_records where active=true; 
 
"Bitmap Heap Scan on call_records (cost=5484.82..15344.49 rows=500567 width=21) (actual time=56.542..172.084 rows=500017 loops=1)" 
" Filter: active" 
" Heap Blocks: exact=7354" 
" -> Bitmap Index Scan on call_records_active_idx (cost=0.00..5359.67 rows=250567 width=0) (actual time=55.040..55.040 rows=500023 loops=1)" 
"  Index Cond: (active = true)" 
"Planning time: 0.105 ms" 
"Execution time: 204.209 ms" 

Dann aktualisiert ich "aktiv", die Statistiken aktualisiert und erneut geprüft.

update call_records 
set active = true 
where id < 750000; 

analyze call_records; 
explain analyze 
select * from call_records where active=true; 
 
"Seq Scan on call_records (cost=0.00..22868.00 rows=874100 width=21) (actual time=0.032..280.506 rows=874780 loops=1)" 
" Filter: active" 
" Rows Removed by Filter: 125220" 
"Planning time: 0.316 ms" 
"Execution time: 337.400 ms" 

sequenzielle Scans Ausschalten zeigt, dass in meinem Fall, PostgreSQL die richtige Entscheidung getroffen. Der Tabellen-Scan (sequentieller Scan) war ca. 10 ms schneller.

set enable_seqscan = off; 
explain analyze 
select * from call_records where active=true; 
 
"Index Scan using call_records_active_idx on call_records (cost=0.42..39071.14 rows=874100 width=21) (actual time=0.031..293.295 rows=874780 loops=1)" 
" Index Cond: (active = true)" 
"Planning time: 0.343 ms" 
"Execution time: 349.403 ms" 
+0

Große Bedeutung. – Viren

+0

ist ihre beliebige Quelle, wo es erwähnt wird. – Viren

+1

@Viren: Abfrageplanung ist sehr komplex. Aber es ist alles grundlegende Logik, wenn Sie es brechen. Beginnen Sie vielleicht mit dem Kapitel * ["Statistiken, die vom Planer verwendet werden"] (https://www.postgresql.org/docs/current/static/planner-stats.html) * im Handbuch. Und alles von * ["Wie der Planer Statistiken verwendet"] (https://www.postgresql.org/docs/current/static/planner-stats-details.html) * für die blutigen Details. Es hängt von vielen Faktoren ab, aber ein Index-Scan zahlt normalerweise nur, wenn Sie nur ~ 5% oder weniger aus einer Tabelle auswählen. Es ist wesentlich mehr Aufwand als bei einem einfachen, dummen sequentiellen Scan. –

2

Sie mit dem Testen der Kosten des Index-Scan

SET enable_seqscan = OFF; 

Sie es werden sehen, beginnen sollte ist viel höher als die seqscan. Sie haben wahrscheinlich eine sehr niedrige Anzahl aktiver Zeilen in Ihrer Tabelle. Da Sie * auswählen, muss Postgres immer noch jede Zeile nachschlagen, und so ist es viel einfacher, einen sequenziellen Scan für alle Zeilen durchzuführen, anstatt den Index zu überprüfen und dann die meisten Seiten zu holen.

Verwandte Themen