Ich muss Update einer relativ sehr großen Tabelle (80M Datensätze) Invoice_Payment
durchführen. Es sollte Daten von einer anderen Tabelle Invoice_Payment_updated
aktualisieren, die 10% -15% von Invoice_Payment
in Zeilenanzahl ist. Zur Veranschaulichung bitte einen Blick auf die folgende Demo-Tabellen nehmen:Der beste Ansatz zur Verbesserung der Abfrageleistung bei der Aktualisierung großer Tabelleninhalte
Invoice_Payment Invoice_Payment_updated
--------------- -----------------------
Customer_id Invoice_no Id Cust_id Invoice_no
10 10100001 1 10 20200100
11 10100002 2 11 20200101
12 10100003
13 10100004
Ich weiß Merge in der Regel eine UPSERT verwendet wird, um auszuführen und es dauert länger mehrmals als Aussage äquivalent Aktualisierung auszuführen. Im Vergleich dazu gibt es jedoch Fälle, in denen eine normale update-Anweisung mit mehreren Unterabfragen zu einer geringeren Leistung führt.
MERGE INTO Invoice_Payment ip
USING (SELECT ipu.Cust_id, ipu.Invoice_no from Invoice_Payment_updated ipu
INNER JOIN Invoice_Payment ip ON ip.Customer_id = ipu.Cust_id
WHERE ipu.Cust_id = ip.Customer_id and ipu.Invoice_no <> ip.Invoice_no) t
ON (ip.Customer_id = t.Cust_id)
WHEN MATCHED THEN
UPDATE SET ip.Invoice_no = t.Invoice_no;
Um die Leistung zu verbessern, kann ich Batch auf die Updates ROWCOUNT verwenden, aber das wird die Ausführung nicht beschleunigen, wird es nur mit der Verringerung Gesamtsperr helfen.
einfache Update-Anweisung Im Anschluss an die gleiche Leistung zurückgibt:
eine sehr clevere eine SQL Merge und aktualisieren istUPDATE Invoice_Payment
SET Invoice_no = (SELECT ipu.Invoice_no
FROM Invoice_Payment_updated ipu
WHERE ipu.Cust_id = Invoice_Payment.Customer_id
AND ipu.Invoice_no <> Invoice_Payment.Invoice_no)
WHERE EXISTS (SELECT 1
FROM Invoice_Payment_updated ipu
WHERE ipu.Cust_id = Invoice_Payment.Customer_id
AND ipu.Invoice_no <> Invoice_Payment.Invoice_no);
Idee zu verwenden, aber ich hörte, dass sie beide in Performance-Probleme schlägt fehl, wenn ich viele Datensätze aktualisieren müssen (dh über 75M) in einem großen und breiten Tisch. Darüber hinaus ist das Wiederherstellen der gesamten Tabelle eine Menge IO-Last, ganz zu schweigen davon, dass sie viel Platz in Anspruch nehmen wird, um die Tabelle aufgrund von Unterabfragen vorübergehend mehrmals speichern zu lassen.
Ein weiterer Ansatz, um dieses Problem anhand der temporäre Tabelle zu beheben:
CREATE TABLE tmp (
Cust_id int,
Invoice_no int);
INSERT INTO tmp_stage VALUES
(SELECT ipu.Cust_id, ipu.Invoice_no FROM Invoice_Payment_updated ipu
INNER JOIN Invoice_Payment ip ON ip.Customer_id = ipu.Cust_id
WHERE ipu.Cust_id = ip.Customer_id and ipu.Invoice_no <> ip.Invoice_no);
UPDATE (SELECT tmp.Cust_id, ip.Customer_id, tmp.Invoice_no, tgt.Invoice_no
FROM tmp INNER JOIN Invoice_Payment ip
ON tmp.Cust_id = ip.Customer_id)
SET tmp.Invoice_no = ip.Invoice_no;
I, die ein, um herauszufinden, will, ist besser im Fall von mehreren Unterabfragen verwenden?
Alle Gedanken sind willkommen und eine völlig andere Lösung des ursprünglichen Problems wird sehr geschätzt.
Hallo, bitte lesen Sie durch diesen Artikel, es wird eine Menge helfen: http://www.orafaq.com/node/2450 – Thomas
@Thomas Seien Sie vorsichtig mit diesem Artikel, es ist einfach, die falsche Schlussfolgerung zu ziehen. So wie die Informationen präsentiert werden, mag man denken, dass # 8 die schnellste ist, aber # 7 ist genauso schnell. Der letzte Anhang widerspricht den Ergebnissen. –
@JonHeller das ist warum ich schrieb "durchlesen", in jedem einzelnen Fall könnte fast einen Unterschied machen 1-1 Lösung, ich weiß es. Das beste Schlagwort in Orakel ist "Probier es aus und untersuche die Ergebnisse" – Thomas