PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

postgresql generuje sekwencję bez przerw

Sekwencje nie generują zestawów liczb bez przerw i naprawdę nie ma możliwości, aby to zrobiły, ponieważ cofnięcie lub błąd „wykorzysta” numer sekwencji.

Jakiś czas temu napisałem na ten temat artykuł. Jest skierowany do Oracle, ale tak naprawdę dotyczy podstawowych zasad liczb bez przerw i myślę, że to samo dotyczy tutaj.

Cóż, to się powtórzyło. Ktoś zapytał, jak zaimplementować wymóg generowania serii liczb bez przerw i sprowadził na nich rój pesymistów, którzy powiedzieli (i tu trochę parafrazuję), że to zabije wydajność systemu, to rzadko jest to słuszne wymaganie , że ktokolwiek napisał ten wymóg jest idiotą bla bla bla.

Jak wspomniałem w wątku, czasami prawdziwym wymogiem prawnym jest generowanie serii liczb bez przerw. Numery faktur dla ponad 2 000 000 organizacji w Wielkiej Brytanii, które są zarejestrowane jako VAT (podatek od sprzedaży), mają taki wymóg, a powód jest dość oczywisty:utrudnia to ukrycie generowania przychodów przed organami podatkowymi. Widziałem komentarze, że jest to wymóg w Hiszpanii i Portugalii i nie zdziwiłbym się, gdyby nie był to wymóg w wielu innych krajach.

Jeśli więc przyjmiemy, że jest to słuszne wymaganie, w jakich okolicznościach bezprzerwowe serie liczb* stanowią problem? Myślenie grupowe często sprawia, że ​​wierzysz, że zawsze tak jest, ale w rzeczywistości jest to potencjalny problem tylko w bardzo szczególnych okolicznościach.

  1. Seria liczb nie może zawierać przerw.
  2. Wiele procesów tworzy podmioty, z którymi powiązany jest numer (np. faktury).
  3. Liczby muszą zostać wygenerowane w momencie tworzenia jednostki.

Jeśli wszystkie te wymagania muszą być spełnione, oznacza to, że w aplikacji znajduje się punkt serializacji i omówimy to za chwilę.

Najpierw porozmawiajmy o metodach implementacji wymagania szeregu liczb, jeśli możesz odrzucić którekolwiek z tych wymagań.

Jeśli seria liczb może zawierać luki (i masz wiele procesów wymagających natychmiastowego wygenerowania liczby), użyj obiektu Oracle Sequence. Mają bardzo wysoką wydajność, a sytuacje, w których można się spodziewać luk, zostały bardzo dobrze omówione. Nie jest zbyt trudne zminimalizowanie liczby pomijanych liczb poprzez podejmowanie wysiłków projektowych, aby zminimalizować ryzyko niepowodzenia procesu między wygenerowaniem liczby a zatwierdzeniem transakcji, jeśli jest to ważne.

Jeśli nie masz wielu procesów tworzących encje (i potrzebujesz pozbawionej przerw serii liczb, które muszą być wygenerowane natychmiast), jak może to mieć miejsce w przypadku zbiorczego generowania faktur, to masz już punkt serializacji. To samo w sobie może nie stanowić problemu i może być skutecznym sposobem wykonania wymaganej operacji. Generowanie liczb bez przerw jest w tym przypadku dość trywialne. Możesz odczytać bieżącą wartość maksymalną i zastosować wartość przyrostową do każdego podmiotu za pomocą wielu technik. Na przykład, jeśli wstawiasz nową partię faktur do tabeli faktur z tymczasowej tabeli roboczej, możesz:

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

Oczywiście możesz chronić swój proces tak, aby tylko jedna instancja mogła działać na raz (prawdopodobnie z DBMS_Lock, jeśli używasz Oracle) i chronić fakturę # unikalnym ograniczeniem klucza i prawdopodobnie sprawdzać brakujące wartości za pomocą oddzielnego kodu, jeśli naprawdę cię to obchodzi.

Jeśli nie potrzebujesz natychmiastowego generowania liczb (ale potrzebujesz ich bez przerw i wiele procesów generuje encje), możesz zezwolić na generowanie encji i zatwierdzenie transakcji, a następnie pozostawić generowanie numeru do jednej partii stanowisko. Aktualizacja tabeli encji lub wstawienie do osobnej tabeli.

Więc jeśli potrzebujemy trifecta natychmiastowego generowania szeregu liczb bez przerw przez wiele procesów? Wszystko, co możemy zrobić, to spróbować zminimalizować okres serializacji w procesie, a ja oferuję następujące porady i z zadowoleniem przyjmuję wszelkie dodatkowe porady (lub oczywiście porady).

  1. Przechowuj bieżące wartości w dedykowanej tabeli. NIE używaj sekwencji.
  2. Upewnij się, że wszystkie procesy używają tego samego kodu do generowania nowych liczb, umieszczając je w funkcji lub procedurze.
  3. Serializuj dostęp do generatora numerów za pomocą DBMS_Lock, upewniając się, że każda seria ma swoją własną dedykowaną blokadę.
  4. Przytrzymaj blokadę w generatorze serii, aż transakcja tworzenia encji zostanie zakończona, zwalniając blokadę przy zatwierdzeniu
  5. Opóźnij generowanie numeru do ostatniego możliwego momentu.
  6. Rozważ wpływ nieoczekiwanego błędu po wygenerowaniu liczby i przed zakończeniem zatwierdzania — czy aplikacja zostanie bezpiecznie wycofana i zwolni blokadę, czy też utrzyma blokadę w generatorze szeregów do czasu późniejszego rozłączenia sesji? Niezależnie od zastosowanej metody, jeśli transakcja się nie powiedzie, numery seryjne muszą zostać „zwrócone do puli”.
  7. Czy możesz zawrzeć całość w wyzwalaczu w tabeli encji? Czy możesz zawrzeć to w tabeli lub innym wywołaniu API, które wstawia wiersz i automatycznie zatwierdza wstawienie?

Artykuł oryginalny



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nazwy procesów PostgreSQL w systemie Solaris

  2. Jak cbrt() działa w PostgreSQL

  3. Jak dodać liczbę dni w postgresql datetime

  4. PostgreSQL 13:OGRANICZENIE… Z WIĘZAMI

  5. Benchmarking Postgres-XL