2016-10-13 2 views
0

Lauf Postgres 9,5Warum verwendet diese Abfrage nicht die Indizes, die ich erstellt habe?

SELECT events.id, events.start_time, events.host_id, events.title from events 
JOIN accountsevents ON accountsevents.events_id = events.id 
WHERE accountsevents.accounts_id = %(account_id)s OR events.host_id = %(account_id)s 
GROUP BY events.id 
ORDER BY start_time DESC 

Ich habe diese Abfrage und Postgres sagt der Kosten über 100k ist. Scheint übertrieben. Dies ist die einzige Abfrage, die ich nicht die Indizes verwende, die ich für jede Tabelle erstellt habe.

Ich fühle mich wie der Index falsch eingerichtet ist oder ich nur etwas mit der Abfrage fehlt. Die ersten Sequenz-Scans töten es.

ADDED EXPLAIN VERBOSE

"Sort (cost=124388.27..124390.10 rows=732 width=40) (actual time=1533.902..1533.928 rows=470 loops=1)" 
" Output: events.id, events.start_time, events.host_id, events.title" 
" Sort Key: events.start_time DESC" 
" Sort Method: quicksort Memory: 66kB" 
" -> HashAggregate (cost=124346.12..124353.44 rows=732 width=40) (actual time=1533.658..1533.759 rows=470 loops=1)" 
"  Output: events.id, events.start_time, events.host_id, events.title" 
"  Group Key: events.id" 
"  -> Hash Join (cost=4912.30..124344.29 rows=732 width=40) (actual time=56.671..1532.831 rows=971 loops=1)" 
"    Output: events.id, events.start_time, events.host_id, events.title" 
"    Hash Cond: (accountsevents.events_id = events.id)" 
"    Join Filter: ((accountsevents.accounts_id = 1) OR (events.host_id = 1))" 
"    Rows Removed by Join Filter: 2761882" 
"    -> Seq Scan on public.accountsevents (cost=0.00..45228.52 rows=2762852 width=8) (actual time=0.005..466.094 rows=2762853 loops=1)" 
"     Output: accountsevents.events_id, accountsevents.accounts_id" 
"    -> Hash (cost=2795.91..2795.91 rows=104191 width=40) (actual time=53.579..53.579 rows=104181 loops=1)" 
"     Output: events.id, events.start_time, events.host_id, events.title" 
"     Buckets: 65536 Batches: 4 Memory Usage: 2462kB" 
"     -> Seq Scan on public.events (cost=0.00..2795.91 rows=104191 width=40) (actual time=0.004..26.171 rows=104181 loops=1)" 
"       Output: events.id, events.start_time, events.host_id, events.title" 
"Planning time: 0.201 ms" 
"Execution time: 1534.024 ms" 
+1

Bitte bearbeiten Sie Ihre Frage und fügen Sie den Ausführungsplan hinzu, der mit 'explain (analyse, verbose)' generiert wurde. [_Formatted_] (http://stackoverflow.com/editing-help#code) ** Text ** bitte, [keine Screenshots] (http://meta.stackoverflow.com/questions/285551/why-may-i -nicht-upload-images-of-code-auf-so-wenn-eine-Frage/285557 # 285557) –

+0

Ich habe die EXPLAIN hinzugefügt – DigitalDisaster

+0

Sieht so aus, als ob Sie einen Index auf 3 Spalten haben und Sie nur 2 Spalten verwenden in der Abfrage. Der Index erfordert alle 3. (id, accounts_id, events_id) Ich würde id als Primärschlüssel-Index verwenden und einen weiteren für accounts_id & events_id hinzufügen. – winkbrace

Antwort

3

Kein Index, den Sie mit dieser Abfrage helfen.

Das Problem ist, dass Sie ein OR im WHERE Zustand haben, so ist es nicht möglich, einen Filter vor die Tabellen verbunden sind, anzuwenden, das ist, wo ein Index Ihnen helfen könnte. Versuchen Sie, die OR durch eine AND zu ersetzen und sehen Sie, wie PostgreSQL viel besser machen kann.

Auf diese Weise PostgreSQL das Ganze zu berechnen hat kommen und nur die Zeilen herausfiltern danach kann die große Anzahl von Reihen von Join Filter entfernt – zu sehen.

Die einzige Sache, für die ein Index verwendet werden könnte, wäre eine Nested-Loop-Join, und das wäre viel teurer. Ich denke also nicht, dass es einen besseren Plan für diese Abfrage gibt.

Sie können sehen, dass die PostgreSQL-Schätzungen der Anzahl der Zeilen ziemlich gut sind, was normalerweise ein Zeichen dafür ist, dass PostgreSQL tatsächlich das Richtige getan hat.

Vielleicht können Sie mit einer Abfrage wie

SELECT * FROM 
    (SELECT ... FROM events JOIN accountsevents ON ... 
     WHERE accountsevents.accounts_id = 1 
    UNION 
    SELECT ... FROM events JOIN accountsevents ON ... 
     WHERE events.host_id = 1) sub 
GROUP BY ... ORDER BY ... 

besser machen, aber ich würde nicht auf sie wetten.
(Hinweis: Diese Abfrage ist semantisch etwas anders, aber vielleicht spielt es in Ihrem Fall keine Rolle.)

Verwandte Themen