Query dauert viel zu lange

Ich habe folgendes SQL Statement:

select distinct sr.styleid, sr.gender, se.agemin * 1000 + se.agemax as agegroup 
from swimresult sr
left join swimevent se on se.swimeventid = sr.swimeventid  
left join swimresult sr2 on sr.gender=sr2.gender and sr.styleid=sr2.styleid and sr.course = sr2.course
left join recorditem ri on ri.swimresultid = sr2.swimresultid and ri.recordlistid = 50069 
where sr.meetid = 627794 and sr.place = 1 and sr.styleid <= 20 and se.agemin >= 25 and ri.swimresultid is null

Ich weiss, ein left join ist immer langsam aber über den Filter sr.meetid = 62774 habe ich ein Kriterium das aus der Tabelle mit mehreren Millionen Datensätzen etwa 2000 Datensätze auswählt. Das Query läuft ewigs, nach 15 Minuten habe ich abgebrochen.
Was mache ich falsch?

Christian

Zeig uns das EXPLAIN, und wenn möglich das EXPLAIN ANALYSE dazu. Sowie Tabellendefinitionen aller beteiligten Tabellen.

Das ist das Explain, Analyze:

Unique  (cost=2192078.91..2302029.83 rows=682158 width=8) (actual time=1456116.838..1625111.102 rows=252 loops=1)
  ->  Sort  (cost=2192078.91..2219566.64 rows=10995092 width=8) (actual time=1456116.826..1567525.031 rows=345652197 loops=1)
        Sort Key: sr.styleid, sr.gender, (((se.agemin * 1000) + se.agemax))
        Sort Method: external merge  Disk: 6082384kB
        ->  Hash Anti Join  (cost=447.75..820283.31 rows=10995092 width=8) (actual time=1.892..1136980.974 rows=345652197 loops=1)
              Hash Cond: (sr2.swimresultid = ri.swimresultid)
              ->  Nested Loop Left Join  (cost=1.57..626047.60 rows=10995184 width=12) (actual time=1.028..1041147.024 rows=345656055 loops=1)
                    ->  Nested Loop  (cost=1.00..2234.11 rows=9 width=10) (actual time=0.170..8.058 rows=252 loops=1)
                          ->  Index Scan using ix_swimresult_meet on swimresult sr  (cost=0.57..1771.59 rows=189 width=10) (actual time=0.093..2.300 rows=279 loops=1)
                                Index Cond: ((meetid = 627794) AND (styleid <= 20))
                                Filter: (place = 1)
                                Rows Removed by Filter: 735
                          ->  Index Scan using pk_swimevent on swimevent se  (cost=0.43..2.45 rows=1 width=8) (actual time=0.014..0.014 rows=1 loops=279)
                                Index Cond: (swimeventid = sr.swimeventid)
                                Filter: (agemin >= 25)
                                Rows Removed by Filter: 0
                    ->  Index Scan using ix_swimresult_style on swimresult sr2  (cost=0.57..68364.09 rows=94852 width=10) (actual time=0.077..3893.551 rows=1371651 loops=252)
                          Index Cond: ((sr.course = course) AND (sr.gender = gender) AND (sr.styleid = styleid))
              ->  Hash  (cost=438.21..438.21 rows=638 width=4) (actual time=0.838..0.838 rows=723 loops=1)
                    Buckets: 1024  Batches: 1  Memory Usage: 34kB
                    ->  Bitmap Heap Scan on recorditem ri  (cost=10.23..438.21 rows=638 width=4) (actual time=0.195..0.732 rows=723 loops=1)
                          Recheck Cond: (recordlistid = 50069)
                          Heap Blocks: exact=25
                          ->  Bitmap Index Scan on ix_recorditem_recordlist  (cost=0.00..10.07 rows=638 width=0) (actual time=0.172..0.172 rows=723 loops=1)
                                Index Cond: (recordlistid = 50069)
Planning Time: 3.378 ms
Execution Time: 1625568.634 ms

Die Tabellen SWIMRESULT, SWIMEVENT und RANKINGITEM haben alle ein Primarykey auf dem ID Feld.

Hast Du mal versucht die LEFT JOINs durch NOT EXIST Bedingungen zu ersetzen? Dann kannst Du vermutlich auch das DISTINCT weglassen:

select sr.styleid, sr.gender, se.agemin * 1000 + se.agemax as agegroup 
from swimresult sr
  left join swimevent se on se.swimeventid = sr.swimeventid  
where sr.meetid = 627794 
  and sr.place = 1 
  and sr.styleid <= 20 
  and se.agemin >= 25 
  and not exists (select * 
                  from recorditem ri
                    join swimresult sr2 on ri.swimresultid = sr2.swimresultid
                  where ri.recordlistid = 50069
                    and sr.gender = sr2.gender 
                    and sr.styleid = sr2.styleid 
                    and sr.course = sr2.course)

RANKINGITEM gibt es nicht im Explain / SQL.

Das not exists ist vielleicht die Lösung, aber es wird ja durch die “recht offene” Einschränkung zurück sr gender, styleid und course irgendwie ins Knie getreten.
Überhaupt finde ich den Join über die 3 Felder sehr schwach. Fehlt vielleicht ein join kriterium? Und muss wirklich alles Outer sein?
Und wäre ri.recordlistid = 50069 nicht eher where clause?

Danke für die Hinweise. Ich habe das Problem nun mit zwei separaten SQL und ein paar Zeilen Code gelöst.

Christian