Ich versuche, eine Zwischenspeichertabelle ('neue Daten') mit einer anderen Tabelle ('vorhandene Daten') zu vergleichen, um hinzugefügte/geänderte/entfernte Zeilen und schließlich ein Upsert zu identifizieren. Dies ist eine teure Operation - ein vollständiger Unterschied in einem großen Datensatz. Ich wollte wirklich den EXCEPT
Befehl für syntaktische Klarheit verwenden, aber habe ernsthafte Leistungsprobleme damit, und finde einen LEFT JOIN
ist viel besser.Redshift EXCEPT viel langsamer als LEFT JOIN
Die beiden Tabellen haben eine ähnliche Anzahl von Zeilen und das gleiche Schema (fast - die 'zweite' Tabelle hat eine zusätzliche created_date
Spalte).
Beide teilen distkey(date)
und sortkey(date, id1, id2)
; Ich gebe sogar die Spalten in der 'richtigen' Reihenfolge innerhalb der EXCEPT
-Anweisung an, um dem Optimierer zu helfen.
Die Abfragepläne für jede, auf einer Testgröße-Teilmenge der Daten, sind unten.
explain
select date, id1, id2, id3, value, attr1, attr2, attr3 from new_data
except select date, id1, id2, id3, value, attr1, attr2, attr3 from existing_data;
XN SetOp Except (cost=1000002817944.78..1000003266822.61 rows=1995013 width=1637)
-> XN Sort (cost=1000002817944.78..1000002867820.09 rows=19950126 width=1637)
Sort Key: date, id1, id2, id3, value, attr1, attr2, attr3
-> XN Append (cost=0.00..399002.52 rows=19950126 width=1637)
-> XN Subquery Scan "*SELECT* 1" (cost=0.00..199501.26 rows=9975063 width=1637)
-> XN Seq Scan on new_data (cost=0.00..99750.63 rows=9975063 width=1637)
-> XN Subquery Scan "*SELECT* 2" (cost=0.00..199501.26 rows=9975063 width=1636)
-> XN Seq Scan on existing_data (cost=0.00..99750.63 rows=9975063 width=1636)
Vergleichen mit meinem viel hässlicher LEFT JOIN
explain
select t1.* from new_data t1
left outer join existing_data t2 on
t1.date = t2.date
and t1.id1 = t2.id1
and coalesce(t1.id2, -1) = coalesce(t2.id2, -1)
and coalesce(t1.id3, -1) = coalesce(t2.id3, -1)
and coalesce(t1.value, -1) = coalesce(t2.value, -1)
and coalesce(t1.attr1, '') = coalesce(t2.attr1, '')
and coalesce(t1.attr2, '') = coalesce(t2.attr2, '')
and coalesce(t1.attr3, '') = coalesce(t2.attr3, '')
where t2.id1 is null;
XN Merge Left Join DS_DIST_NONE (cost=0.00..68706795.68 rows=9975063 width=1637)
Merge Cond: (("outer".date = "inner".date) AND (("outer".id1)::bigint = "inner".id1))
Join Filter: (((COALESCE("outer".id2, -1))::bigint = COALESCE("inner".id2, -1::bigint)) AND ((COALESCE("outer".id3, -1))::bigint = COALESCE("inner".id3, -1::bigint)) AND ((COALESCE("outer".value, -1::numeric))::double precision = COALESCE("inner".value, -1::double precision)) AND ((COALESCE("outer".attr1, ''::character varying))::text = (COALESCE("inner".attr1, ''::character varying))::text) AND ((COALESCE("outer".attr2, ''::character varying))::text = (COALESCE("inner".attr2, ''::character varying))::text) AND ((COALESCE("outer".attr3, ''::character varying))::text = (COALESCE("inner".attr3, ''::character varying))::text))
Filter: ("inner".id1 IS NULL)
-> XN Seq Scan on new_data t1 (cost=0.00..99750.63 rows=9975063 width=1637)
-> XN Seq Scan on existing_data t2 (cost=0.00..99750.63 rows=9975063 width=1636)
Die Abfragekosten sind 1000003266822.61
vs 68706795.68
. Ich weiß, dass ich keine Queries vergleichen soll, aber es hat sich in den Ausführungszeiten bewährt. Irgendwelche Ideen, warum eine EXCEPT
Aussage ist so viel langsamer als eine LEFT JOIN
hier?