Frage

Ich habe eine DB-Tabelle, in der jede Zeile einen zufällig erzeugte Primärschlüssel hat, eine Nachricht und einen Benutzer. Jeder Benutzer hat etwa 10-100 Nachrichten, aber es gibt 10k-50k-Benutzer.

Ich schreibe die Nachrichten täglich für jeden Benutzer in einem Rutsch. Ich möchte die alten Nachrichten für jeden Benutzer wegzuwerfen, bevor die neuen Schreiben der Tabelle so klein wie möglich zu halten.

Im Moment habe ich dies effektiv tun:

delete from table where user='mk'

Dann schreiben Sie alle Nachrichten für diesen Benutzer. Ich habe viel Streit zu sehen, weil ich viele Fäden haben diese zugleich zu tun.

ich habe eine zusätzliche Anforderung, den neuesten Satz von Nachrichten für jeden Benutzer zu erhalten.

Ich habe keinen Zugriff auf die DB direkt. Ich versuche, das Problem auf einige aus zweiter Hand Feedback basiert zu erraten. Der Grund, warum ich auf diesem Szenario bin konzentriert ist, dass die Löschabfrage (wieder - zum besten meines Wissens) eine Menge Wartezeit zeigt. Plus es ist ein neu hinzugefügtes Bit Funktionalität

Kann jemand einen Rat anbieten?

Wäre es besser:

select key from table where user='mk'

Dann löschen Sie einzelne Zeilen von dort? Ich denke, dass weniger brutal Verriegelung führen könnte.

War es hilfreich?

Lösung

Nein, es ist immer besser, eine einzelne SQL-Anweisung auf einem Satz von Zeilen als eine Reihe von „Zeile-für-Zeile“ durchführt (oder was Tom Kyte „slow-by-langsam“ nennt) Operationen. Wenn Sie sagen, Sie sind „eine Menge Konkurrenz sehen“, was sehen Sie genau? Eine offensichtliche Frage: ist Spalte USER indiziert

(Natürlich kann der Spaltenname wirklich nicht USER in einer Oracle-Datenbank sein, da es ein reserviertes Wort ist!)

EDIT: Sie haben gesagt, dass Spalte USER nicht indiziert ist. Das bedeutet, dass jeder einen vollständigen Tabellenscan beinhaltet löschen wird bis zu 50K * 100 = 5.000.000 Zeilen (oder bestenfalls 10K * 10 = 100.000 Zeilen) gerade einmal 10 bis 100 Zeilen zu löschen. einen Index für Benutzer hinzufügen können Ihre Probleme lösen.

Andere Tipps

Wenn Sie das jeden Tag tun für jeden Anwender, warum nicht nur jeden Datensatz aus der Tabelle in einer einzigen Anweisung löschen? Oder sogar

truncate table whatever reuse storage
/

Bearbeiten

Der Grund, warum ich dieser Ansatz vorschlagen, ist, dass der Prozess wie eine tägliche Batch-Upload von Benutzernachrichten von einer Lichtung aus den alten Nachrichten vorangestellt sieht. Das heißt, scheint die Geschäftsregeln zu mir sein „die Tabelle nur einen Tag im Wert von Nachrichten für einen bestimmten Benutzer halten wird“. Wenn dieser Prozess für jeden Benutzer erfolgt dann eine einzige Operation wäre die effizienteste.

Wenn Benutzer jedoch nicht bekommen einen frischen Satz von Nachrichten jeden Tag und es ist eine Tochtergesellschaft Regel, die uns die jüngste Gruppe von Nachrichten für jeden Benutzer dann die gesamte Tabelle Zappen zu halten erfordert würde falsch liegen.

Sind Sie sicher, dass Sie Sperrenkonflikte sind zu sehen? Es scheint wahrscheinlicher, dass Sie Datenträger Anstoßes sind zu sehen, da zu viele gleichzeitige (aber in keinem Zusammenhang Updates). Die Lösung ist einfach, dass die Anzahl der Threads zu reduzieren Sie verwenden:. Weniger Plattenkonkurrenz höheren Gesamtdurchsatz bedeuten

Ich glaube, Sie benötigen, um Ihre Anforderungen etwas klarer definieren ...

Zum Beispiel. Wenn Sie alle Benutzer wissen, wer Sie zu Nachrichten schreiben wollen, legen Sie die IDs in eine temporäre Tabelle, einen Index auf ID und Batch löschen. Dann werden die Fäden Sie weg feuern tun zwei Dinge. Schreiben Sie die ID des Benutzers auf eine temporäre Tabelle, schreiben Sie die Nachricht an eine andere temporäre Tabelle. Dann, wenn die Fäden mit der Ausführung fertig, der Haupt-Thread sollte

DELETE * FROM Nachrichten INNER JOIN TEMP_MEMBERS ON ID = TEMP_ID

INSERT INTO NACHRICHTEN SELECT * FROM TEMP_messges

im nicht vertraut mit Oracle-Syntax, aber das ist die Art, wie ich es wäre leichter, wenn die Benutzer Nachrichten all in schnellen Folge durchgeführt werden.

Hope, das hilft

Sprechen Sie mit Ihrem DBA

Er ist da, um Ihnen zu helfen. Wenn wir DBAs Zugang weg von den Entwicklern für etwas wie dies, wird angenommen, wir die Unterstützung für Sie für diese Aufgabe zur Verfügung stellen. Wenn Ihr Code zu lange dauert abzuschließen und diese Zeit wird in der Datenbank gebunden zu werden, wird Ihr DBA der Lage sein, genau zu schauen, was los ist, und bieten Anregungen oder vielleicht sogar das Problem zu lösen, ohne dass Sie etwas ändern.

Nur über Ihre Problemstellung Blick, ist es nicht angezeigt, die Sie im Streit Fragen suchen würden, aber ich weiß nichts über die zugrunde liegende Struktur.

Wirklich, zu Ihrem DBA sprechen. Er wird wahrscheinlich auf etwas Spaß genießen suchen, anstatt die Planung die neueste CPU-Bereitstellung.

Dies könnte die Dinge beschleunigen:

Erstellen Sie eine Lookup-Tabelle:

create table rowid_table (row_id ROWID ,user VARCHAR2(100));
create index rowid_table_ix1 on rowid_table (user);

Führen Sie einen nächtlichen Job:

truncate table rowid_table;
insert /*+ append */ into rowid_table
select ROWID row_id , user
from table;
dbms_stats.gather_table_stats('SCHEMAOWNER','ROWID_TABLE');

Dann, wenn das Löschen der Datensätze:

delete from table
where ROWID IN (select row_id
                from rowid_table
                where user = 'mk');

Ihr eigener Vorschlag scheint sehr sinnvoll. Sperren in kleinen Chargen hat zwei Vorteile:

  • werden die Transaktionen kleiner
  • Verriegelung wird in einer Zeit
  • auf nur wenige Zeilen beschränkt werden

Locking in Chargen sollte eine große Verbesserung sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top