PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

postgresql erzeugt Sequenz ohne Lücke

Sequenzen erzeugen keine lückenlosen Zahlenreihen, und es gibt wirklich keine Möglichkeit, sie dazu zu bringen, weil ein Rollback oder ein Fehler die Sequenznummer "verwenden" wird.

Dazu habe ich vor einiger Zeit einen Artikel geschrieben. Es richtet sich an Oracle, aber es geht wirklich um die Grundprinzipien lückenloser Zahlen, und ich denke, das Gleiche gilt hier.

Nun, es ist wieder passiert. Jemand hat gefragt, wie man eine Anforderung zur Generierung einer lückenlosen Zahlenreihe implementiert, und ein Schwarm von Neinsagern ist über sie hergefallen, um zu sagen (und hier paraphrasiere ich leicht), dass dies die Systemleistung beeinträchtigen wird, das ist selten eine gültige Anforderung , dass derjenige, der die Anforderung geschrieben hat, ein Idiot ist, bla bla bla.

Wie ich im Thread anmerke, ist es manchmal eine echte gesetzliche Anforderung, lückenlose Zahlenreihen zu generieren. Rechnungsnummern für die mehr als 2.000.000 umsatzsteuerlich registrierten Organisationen im Vereinigten Königreich haben eine solche Anforderung, und der Grund dafür ist ziemlich offensichtlich:dass es schwieriger wird, die Generierung von Einnahmen vor den Steuerbehörden zu verbergen. Ich habe Kommentare gesehen, dass dies in Spanien und Portugal erforderlich ist, und ich wäre nicht überrascht, wenn es in vielen anderen Ländern nicht erforderlich wäre.

Wenn wir also akzeptieren, dass es sich um eine gültige Anforderung handelt, unter welchen Umständen sind lückenlose Zahlenreihen* ein Problem? Gruppendenken lässt Sie oft glauben, dass dies immer der Fall ist, aber tatsächlich ist es nur unter ganz bestimmten Umständen ein potenzielles Problem.

  1. Die Zahlenreihe darf keine Lücken haben.
  2. Mehrere Prozesse erstellen die Entitäten, denen die Nummer zugeordnet ist (z. B. Rechnungen).
  3. Die Zahlen müssen zum Zeitpunkt der Erstellung der Entität generiert werden.

Wenn alle diese Anforderungen erfüllt werden müssen, haben Sie einen Serialisierungspunkt in Ihrer Anwendung, und wir werden das gleich besprechen.

Lassen Sie uns zunächst über Methoden zur Implementierung einer Anforderung für Zahlenreihen sprechen, wenn Sie eine dieser Anforderungen fallen lassen können.

Wenn Ihre Zahlenreihe Lücken aufweisen kann (und Sie mehrere Prozesse haben, die eine sofortige Generierung der Zahl erfordern), verwenden Sie ein Oracle Sequence-Objekt. Sie sind sehr leistungsstark und die Situationen, in denen Lücken zu erwarten sind, wurden sehr gut diskutiert. Es ist nicht allzu schwierig, die Anzahl der übersprungenen Nummern zu minimieren, indem Designanstrengungen unternommen werden, um die Wahrscheinlichkeit eines Prozessfehlers zwischen der Generierung der Nummer und dem Festschreiben der Transaktion zu minimieren, falls dies wichtig ist.

Wenn Sie nicht mehrere Prozesse haben, die die Entitäten erstellen (und Sie eine lückenlose Zahlenreihe benötigen, die sofort generiert werden muss), wie dies bei der Batch-Erstellung von Rechnungen der Fall sein kann, dann haben Sie bereits einen Punkt für die Serialisierung. Dies ist an sich möglicherweise kein Problem und kann eine effiziente Möglichkeit zum Ausführen der erforderlichen Operation sein. Die Generierung der lückenlosen Zahlen ist in diesem Fall eher trivial. Sie können den aktuellen Maximalwert ablesen und mit einer Reihe von Techniken einen inkrementierenden Wert auf jede Entität anwenden. Wenn Sie beispielsweise einen neuen Rechnungsstapel aus einer temporären Arbeitstabelle in Ihre Rechnungstabelle einfügen, könnten Sie:

insert into
  invoices
    (
    invoice#,
    ...)
with curr as (
  select Coalesce(Max(invoice#)) max_invoice#
  from   invoices)
select
  curr.max_invoice#+rownum,
  ...
from
  tmp_invoice
  ...

Natürlich würden Sie Ihren Prozess so schützen, dass jeweils nur eine Instanz ausgeführt werden kann (wahrscheinlich mit DBMS_Lock, wenn Sie Oracle verwenden), und die Rechnungsnummer mit einem eindeutigen Schlüsselkontrainst schützen und wahrscheinlich mit separatem Code nach fehlenden Werten suchen, wenn es interessiert dich wirklich sehr.

Wenn Sie keine sofortige Generierung der Nummern benötigen (aber Sie benötigen sie lückenlos und mehrere Prozesse generieren die Entitäten), können Sie zulassen, dass die Entitäten generiert und die Transaktion festgeschrieben werden, und die Generierung der Nummer dann einem einzigen Stapel überlassen Arbeit. Eine Aktualisierung der Entitätstabelle oder eine Einfügung in eine separate Tabelle.

Wenn wir also das Trifecta der sofortigen Generierung einer lückenlosen Zahlenreihe durch mehrere Prozesse brauchen? Alles, was wir tun können, ist zu versuchen, die Dauer der Serialisierung in diesem Prozess zu minimieren, und ich biete die folgenden Ratschläge an und freue mich über jeden zusätzlichen Rat (oder natürlich Gegenratschläge).

  1. Speichern Sie Ihre aktuellen Werte in einer speziellen Tabelle. Verwenden Sie KEINE Sequenz.
  2. Stellen Sie sicher, dass alle Prozesse denselben Code verwenden, um neue Zahlen zu generieren, indem Sie ihn in eine Funktion oder Prozedur kapseln.
  3. Serialisieren Sie den Zugriff auf den Zahlengenerator mit DBMS_Lock und stellen Sie dabei sicher, dass jede Serie über eine eigene dedizierte Sperre verfügt.
  4. Halten Sie die Sperre im Seriengenerator, bis Ihre Entitätserstellungstransaktion abgeschlossen ist, indem Sie die Sperre beim Commit freigeben
  5. Verzögern Sie die Generierung der Nummer bis zum letztmöglichen Moment.
  6. Berücksichtigen Sie die Auswirkungen eines unerwarteten Fehlers nach dem Generieren der Zahl und vor Abschluss des Commit – wird die Anwendung ein ordnungsgemäßes Rollback durchführen und die Sperre freigeben, oder wird sie die Sperre für den Seriengenerator beibehalten, bis die Sitzung später getrennt wird? Welche Methode auch immer verwendet wird, wenn die Transaktion fehlschlägt, müssen die Seriennummer(n) „an den Pool zurückgegeben“ werden.
  7. Können Sie das Ganze in einem Trigger auf der Tabelle der Entität kapseln? Können Sie es in eine Tabelle oder einen anderen API-Aufruf kapseln, der die Zeile einfügt und die Einfügung automatisch festschreibt?

Originalartikel