dondy
Goto Top

Tabelleninhalt differentiell in andere Tabelle schreiben

Hallo zusammen,

ich habe zwei Datenbanken (A und B) und möchte von DB A den Inhalt einer Tabelle regelmäßig in DB B kopieren.
Da sich die Tabelle in DB A regelmäßig ändert (es kommen Datensätze hinzu oder werden entfernt) möchte ich nur die neuen Datensätze in die Tabelle der DB B hinzufügen. Wenn Datensätze aus der DB A gelöscht werden sollen diese weiterhin in DB B erhalten bleiben.
Dies soll ca. alle 5 Minuten passieren.
Ich verwende eine SQL2005 Server mit Windows 2003.

Über die Assistenten im SQL-Server bekomme ich das nicht hin. Hat jemand eine Idee?

MfG

Content-ID: 147826

Url: https://administrator.de/contentid/147826

Ausgedruckt am: 04.11.2024 um 22:11 Uhr

filippg
filippg 28.07.2010 um 21:00:08 Uhr
Goto Top
Hallo,

einen Primärschlüssel hast du ja sicher, sei der Spaltenname id, dann sollte:
INSERT INTO B SELECT * FROM A WHERE A.id NOT IN (SELECT B.id FROM B)
das gewünschte tun.
Zur IN-Klausel schreibt MS "Wenn eine IN-Klausel eine extrem hohe Anzahl von Werten (viele Tausende) enthält, können die Ressourcen überbeansprucht werden" http://msdn.microsoft.com/de-de/library/ms177682.aspx

Ist der primärschlüssel streng monoton steigend (also jeder neue größer als jeder vorherige), dann dürfte auch
INSERT INTO B SELECT * FROM A WHERE A.id > (SELECT MAX(B.id) FROM B)
funktionieren und wäre vermutlich performanter.

Gruß

Filipp
dondy
dondy 29.07.2010 um 14:03:09 Uhr
Goto Top
Hallo Filipp,

vielen Dank für Deine Antwort.
Also einen PK gab es in der Tabelle bisher nicht, habe ich aber nachgeholt.
Leider klappt aber dein oben genanntes Beispiel bei mir nicht, weil ich ja über zwei Datenbankserver hinweg die Abfrage mache.
Nun habe ich mir einen Verbindungsserver gebastelt, der auch funktioniert. Jetzt bekomme ich aber die Abfrage nicht hin.
Folgende Abfrage habe ich erstellt:

INSERT INTO OPENQUERY(SERVER_B,'
SELECT * FROM VIEW a
WHERE a.ID NOT IN (Select * from OPENQUERY(SERVER_B,'SELECT ID FROM Tabelle_B'))')

Bei dieser Abfrage erhalte ich dann einen Syntaxfehler. Wo liegt dieser?
Oder ist es garnicht möglich OPENQUERY's miteinander zu verschachteln?
filippg
filippg 29.07.2010 um 20:38:37 Uhr
Goto Top
Hallo,

hast du a) Zwei Datenbanken innerhalb einer MS SQL-Instanz oder b) zwei DBs in zwei unterschiedlichen MS SQL-Instanzen (meinetwegen auch auf unterschiedlichen physikalischen Servern)?

a) sollte ganz eifnach gehen: INSERT INTO dbB..B SELECT * FROM dbA..A WHERE dbA..A.id NOT IN (SELECT dbB..B.id FROM dbB..B)
sprich: DB-Name.. vor jede Tabelle voranstellen.

b) puh... Mir ist nicht klar, was das VIEW in deinem Statement soll. Aber ob man OPENQUERY jetzt schachteln darf... performant ist das sicher nicht. Was bestimmt funktioniert, wenngleich auch nicht performant, ist die Produktivtabelle erst auf Server B zu kopieren, und dann dort eingangs von mir genannten Query auszuführen.

Gruß

Filipp
Biber
Biber 29.07.2010 um 21:09:18 Uhr
Goto Top
Moin dondy,

ich verstehe den Plan auch nicht ganz und möchte mal nachfragen.
Verstanden habe ich den Plan aus Datensicht -> nur die "neuen" Datensätze von Server A/TabelleA sollen alle 5 Minuten auch in TabelleB auf Server B eingefügt werden. Was auch immer fachlich dahinterstehen mag.

Nicht verstanden habe ich, wen oder was du du denn mit der 5minütlichen Abgleicherei beauftragen oder beschäftigen willst.
Den DB-Server A (am dem ja wohl auch eine produktive Datenerfassungs-Appz rödelt) ?
Den Nur-Lese-DB-Clone auf DB-Server ?
Oder macht das der "man in the middle", der Verbindungsserver?
Oder beide/alle drei?

Wäre es nicht sinnvoller, wenn sich finanziell keine ETL-Applikation rechnet, den CPU-und Netzwerkaufwand ein bisschen zu minimieren dadurch, dass
  • Server A per Trigger jeden neuen Datensatz in eine Tabelle auf seinem Server A (oder auf dem Verbindungsserver) INSERTed sofort wenn ein neuer Satz eingegeben wird (der KANN noch nicht da sein)
  • der Empfangsserver alle x Minuten alle diese Sätze liest, alle inserted und die Zwischentabelle C komplett löscht?

Grüße
Biber
filippg
filippg 29.07.2010 um 21:30:03 Uhr
Goto Top
Hallo,

* Server A per Trigger jeden neuen Datensatz in eine Tabelle auf seinem Server A (oder auf dem Verbindungsserver) INSERTed sofort
wenn ein neuer Satz eingegeben wird (der KANN noch nicht da sein)
das ist natürlich der eleganteste Weg, das ist mir nicht eingefallen!
Allerdings sind die Trigger ein bisschen tückisch, insbesondere, wenn man sich nicht damit auskennt. Z.b. Auslösen des INSERT-Triggers auch bei UPDATE-Vorgängen; Trigger-Aufruf bedeutet nicht, dass genau _eine_ Zeile eingefügt wurde, Trigger kann zum Rollback der ganzen Transaktion führen...

Gruß

Filipp
Biber
Biber 29.07.2010 um 22:18:57 Uhr
Goto Top
Moin filippg,

...sind die Trigger ein bisschen tückisch
Ja schon, ich hatte mal eine Desiree Trigger als Praktikantin, ich weiss es wirklich... und ihre Mutti erst!

Aber WTF kann bei einem Trigger schiefgehen, der einen drömeligen Satz als Kopie in eine DB-Tabelle schreibt, die nicht mal einen PK haben muss (keine Constraint-Verletzungen möglich)?

Und er braucht keinen DELETE- und keinen UPDATE-Trigger (außer die, die er vielleicht schon drin hat).

Die Alternative ist doch -verbessere mich, wenn ich irre-, dass irgendein anspruchsloser Prozess alle gatesverdammten 5 Minuten die komplette Datei zum Lesen sperren muss...
für die Dauer eines INTERSECT-JOINs (wie auch immer M$ den nennt).

Dabei geht die DB-Performance für alle Normal-Anwender runter... jeden Tag.. 365x im Jahr.

Wenn schon so eine Bypass-Schmuddellösung, dann wenigstens umwelt- und ressourcenschonend

Grüße
Biber

P.S. @dondy: Du hast übrigens ein sehr sympathisches Profilbildchen. face-wink