Laden...

Insert Select From - dublikate verhindern

Erstellt von Xynratron vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.136 Views
X
Xynratron Themenstarter:in
1.177 Beiträge seit 2006
vor 15 Jahren
Insert Select From - dublikate verhindern

verwendetes Datenbanksystem: SQL Server 200x

Hallo Zusammen,

Ich hab folgendes Problem: wenn ein Insert in eine Tabelle ausgeführt wird, muss ein Insert in eine Kreuztabelle gemacht werden, um alle gekennzeichneten Datensatzkombinationen zu referenzieren, dabei sollten keine Dublikate vorkomen.

Simpler ausgedrückt:

Insert into Kreuz (t.feld1, t.feld2) 
from (Select a.Feld1, b,Feld1 from (select Feld from Source where Attribut=a) as a 
inner join (select Feld from Source where Attribut=b) as b 
on a.Attribut2=b.Attribut2) as t

hmm, auch nicht simpler...

Anders: wenn in einer Tabelle eine bestimmter Wert geändert wird, dann muss in eine andere Tabelle was notiert werden. Dieses "Was" kommt aus einem komplexeren Select. Dabei wird über bestimmte Attribute eine neue n:m Tabelle erzeugt um Abfragen später kurz und geschmeidig zu halten. Hier bekomme ich allerdings leider doppelte Einträge.

Wie kann ich bei einem

Insert * select from * 

durchsetzten dass keine doppelten Einträge vorkommen.

Constraints scheiden aus, da ja das gesammte Insert fehlschlägt.

Ich habe im Moment 2 Ansätze, wäre aber für einen smarteren sehr zu haben:
1.Erst den Select, dann per c# das Recordset durchgehen und einzelne Inserts machen (Insert bzw. Update) 1.einen Instead Of Insert Trigger schreiben der die Überprüfung vornimmt und dann den Insert bzw. Update vornimmt

Ansatz 1 macht es Kollegen leichter meinen Code zu durchschauen - da nicht an 17 Stellen gesucht werden muss.
Ansatz 2 ist schneller.

Ich hab hier noch das Problem, dass zu viele Datensätze vorkommen. Die Krücke existiert nur weil wir einen nominale Größe von 3 Billionen Datensätzen hätten und diese gerne auf etwas verwertbares reduzieren würden. Da das ganze Kunden abhängig ist und hier auch nur die "Auswahl" des Kunden trifft kann man das mit dynamischem Verhalten auf 5-50 Mio. Datensätze pro Kunde reduzieren. Dies ist verwertbar. Aber ein Insert über 50.000 Datensätze ist halt sehr kostenintensiv. Nur zur Erklärung.

Comments plz.

😃

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

D
496 Beiträge seit 2005
vor 15 Jahren

kannst du nicht einfach bei der abfrage die das resultset der einzufügenden datasätze liefert von vorherein die where clause so erweitern das nur die datensätze abgefragt werden die nicht in der zieltabelle vorkommen?

ich hab jetzt keine kompletten cmd parat aber ungefähr so:

insert into tabelle1(spalte1, spalte2.. )
select spalte1, spalte2...
from tabelle2
where spalte1 not in (select spalte1 from tabelle1)

"Programming is similar to sex. If you make a mistake, you have to support it for the rest of your life."

X
Xynratron Themenstarter:in
1.177 Beiträge seit 2006
vor 15 Jahren

ich weis was du meinst - das ist ein Punkt den ich morgen noch versuchen wollte, aber hier leidet die Performance mit zunehmenden Daten vermutlich noch extremer...

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

1.200 Beiträge seit 2007
vor 15 Jahren

Ich kenne den SQLServer nicht, aber unter Oracle würdest du bei so einem Trigger vermutlich eine Mutating Tables Exception bekommen.

Ausserdem ist bei vielen Datensätzen (not) exists gegenüber (not) in vorzuziehen, das ist in der Regel wesentlich schneller. Im Regelfall kann hier von Indizes besser Gebrauch gemacht werden. In schlägt exists von der Performance her eigentlich nur bei kleinen Listen, aber nicht bei großen subselects.

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

F
4 Beiträge seit 2007
vor 15 Jahren

Hallo,

Falls ich dich richtig verstanden habe, könnten dir "left outer join's" helfen.
Damit kannst du dein Vorhaben relativ einfach umsetzen:


Insert into Kreuz (spalte1, spalte2) 
select distinct
   t.feld1, t.feld2
from (
   Select 
      a.Feld1, b,Feld1 
   from (select Feld from Source where Attribut=a) as a 
      inner join (select Feld from Source where Attribut=b) as b 
           on a.Attribut2=b.Attribut2
   ) as t
   left outer join Kreuz k  -- welche Einträge sind bereits vorhanden
      on k.Spalte1 = t.Feld1
      and k.Spalte2 = t.Feld2
where
   k.Spalte1 is null --darf noch nicht vorhanden sein

1.200 Beiträge seit 2007
vor 15 Jahren

Da finde ich es wesentlich einfacher zu lesen:

insert into tbl a 
select * from tbl2 b 
where not exists 
( 
select 1 from tbl a
where a.Schlüsselkriterium1 = b.Schlüsselkriterium1
and     a.Schlüsselkriterium2 = b.Schlüsselkriterium2
-- asf.
)

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

X
Xynratron Themenstarter:in
1.177 Beiträge seit 2006
vor 15 Jahren

hmm, tja, da hab ich wohl vor lauter Bäumen den Wald nicht mehr gesehen. Die Lösung "left outer .. where is null" hätte mir eigentlich selbst einfallen müssen^^

Werde mich hier aber wohl für Not Exists entscheiden, die Performance dürfte geringfügig besser sein. Mal gucken.

Danke euch für den Denkanstoss

😃

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

1.378 Beiträge seit 2006
vor 15 Jahren

Falls doppelte Rows im Select auftauchen sollten, kannst du diese entweder mit GROUP BY oder DISTINCT rausfiltern.

Und ansonsten ist vielleicht auch der MERGE Befehl für dich interessant.

Lg XXX

X
Xynratron Themenstarter:in
1.177 Beiträge seit 2006
vor 15 Jahren

Soo, hallo zusammen,

nochmal Danke fürs mitdenken. Merge (MSSQL 08) wäre natürlich mit die eleganteste Lösung - aber ich bin grad noch auf 2005 unterwegs.

"Outer Join" vs. "Exits" - hier liegen die Performancevorteile knapp bei Exists - aber dass sind nur 49:51 % - also wirklich knapp. IN hab ich nicht wirklich versucht, denn wie in einer nderen Diskussion ersichtlich arbeitet IN eher wie ein OR Operator - und dass wäre nicht akzeptabel. Denn:

Zur Ausgangslage: Viele Datensätze. 7 Joins zu einer Target-Table. Auf einem mager bestücktem System bin ich da bei 20 min. ohne Ziel-Prüfung zum einfügen für alle Datensätze (6.5Mio). Beim Check zum "vorhandenen" Datensatz bin ich pro Operation bei ca. 10 sek. wobei ca. 100.000 Datensätze gegengeprüft werden. (Ergo ist ein IN bei 100.000 Datensätzen schon verschwendet...)

Das Live-System schafft das in 5-10% der Zeit - mit entsprechenden Indizes beim Select - aber Indezes sprechen ja nur für das einzelne Statement, nicht für die benötigte Lage. (Hier würden die Indizes die Insert-Performance negativ beeinflussen, später brauch ich aber vor allem Select Performance^^) Die Tabelle an sich entspricht aber schon bald einer Index-Tabelle, da nur für das Select benötgte Daten vorgehalten werden (siehe Diskussionen über n:m-Tabellen mit zusätzlichen Informationen in der Zwischentabelle, um einen Join zu vermeiden)

Ich bin der Meinung, dass mit etwas mehr Zeit und Memory-Tables, zusätzlichen Selects etc. eine bessere Perfomance zu erreichen ist. Aber hierfür fehlt mir gerade die Zeit. Erst lauffähig machen, dann nochmal Performance-Tuning.

Trozdem nochmals Danke für die Denkanstösse, hatte ein Brett vor dem Kopf^^

😃

Xynratron

PS: zum Performace Tuning, mit dieser Krücke (Komplexe Zwischentabelle) hab ich im Moment die Performance um ca. 1:100 gesteigert ...

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

X
Xynratron Themenstarter:in
1.177 Beiträge seit 2006
vor 15 Jahren

PPS: das magere Testsystem hat zu wenig Arbeitsspeicher. Euer SQL-Server arbeitet erst wirklich wenn die CPU-Leistung hochgeht. Hierfür sollten mindestens die Index-Tabellen komplett im RAM gehalten werden können. [Wenn ihr genug Ram für die komplette DB habt und die CPU trotzdem bei fast 100% ist, so fehlen euch noch Indizes. (mal Tuning Advisor laufen lassen!) - neulich gefixter Fehler]

Es gab von NEC mal einen Prozessor (und Board) - da waren die furchtbar stolz drauf auf der 150 Mhz-CPU in 64MB-Ram die kompletten Indices einer DB halten zu können und damit echt gute Performance zu erreichen. Lang ists her...

😃

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.