sql >> Databáze >  >> RDS >> PostgreSQL

postgresql generuje sekvenci bez mezery

Sekvence negenerují sady čísel bez mezer a ve skutečnosti neexistuje způsob, jak je přimět, aby to dělaly, protože vrácení nebo chyba „použijí“ pořadové číslo.

Před chvílí jsem o tom napsal článek. Je zaměřen na Oracle, ale ve skutečnosti jde o základní principy čísel bez mezer a myslím, že totéž platí i zde.

No, stalo se to znovu. Někdo se zeptal, jak implementovat požadavek na generování řady čísel bez mezer, a sestoupilo se na ně hejno odpůrců, kteří řekli (a zde mírně parafrázuji), že to zabije výkon systému, to je zřídka platný požadavek , že ten, kdo napsal požadavek, je idiot bla bla bla.

Jak upozorňuji na vláknu, někdy je skutečným právním požadavkem generovat řady čísel bez mezer. Čísla faktur pro více než 2 000 000 organizací ve Spojeném království, které jsou registrovány jako DPH (daň z prodeje), mají takový požadavek a důvod je poměrně zřejmý:že je obtížnější skrývat generování příjmů před daňovými úřady. Viděl jsem komentáře, že je to požadavek ve Španělsku a Portugalsku, a nepřekvapilo by mě, kdyby to nebyl požadavek v mnoha dalších zemích.

Pokud tedy připustíme, že se jedná o platný požadavek, za jakých okolností jsou řady čísel bez mezer* problémem? Skupinové myšlení by vás často přimělo věřit, že tomu tak je vždy, ale ve skutečnosti je to potenciální problém pouze za velmi zvláštních okolností.

  1. Číselná řada nesmí mít žádné mezery.
  2. Několik procesů vytváří entity, ke kterým je číslo přiřazeno (např. faktury).
  3. Čísla musí být vygenerována v době vytvoření entity.

Pokud musí být splněny všechny tyto požadavky, pak máte ve své aplikaci bod serializace a za chvíli to probereme.

Nejprve si promluvme o metodách implementace požadavku na řadu čísel, pokud můžete některý z těchto požadavků vypustit.

Pokud vaše řada čísel může mít mezery (a máte více procesů vyžadujících okamžité generování čísla), použijte objekt Oracle Sequence. Jsou velmi výkonné a situace, ve kterých lze očekávat mezery, byly velmi dobře probrány. Není příliš náročné minimalizovat množství vynechaných čísel tím, že vynaložíte konstrukční úsilí k minimalizaci možnosti selhání procesu mezi vygenerováním čísla a provedením transakce, pokud je to důležité.

Pokud nemáte více procesů vytvářejících entity (a potřebujete řadu čísel bez mezer, která musí být okamžitě generována), jako tomu může být v případě dávkového generování faktur, pak již máte bod serializace. To samo o sobě nemusí být problém a může to být efektivní způsob provedení požadované operace. Generování čísel bez mezer je v tomto případě poměrně triviální. Můžete si přečíst aktuální maximální hodnotu a použít zvyšující se hodnotu na každou entitu pomocí řady technik. Pokud například vkládáte novou dávku faktur do tabulky faktur z dočasné pracovní tabulky, můžete:

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

Samozřejmě byste svůj proces ochránili tak, aby mohla současně běžet pouze jedna instance (pravděpodobně pomocí DBMS_Lock, pokud používáte Oracle), a ochránili byste fakturu# pomocí jedinečného omezení klíče a pravděpodobně zkontrolovali chybějící hodnoty pomocí samostatného kódu, pokud opravdu, opravdu tě to zajímá.

Pokud nepotřebujete okamžité generování čísel (ale potřebujete je bez mezer a entity generuje více procesů), můžete povolit generování entit a potvrzení transakce a poté nechat generování čísla na jednu dávku. práce. Aktualizace tabulky entit nebo vložení do samostatné tabulky.

Pokud tedy potřebujeme trifectu okamžitého generování řady čísel bez mezer pomocí více procesů? Jediné, co můžeme udělat, je pokusit se minimalizovat dobu serializace v tomto procesu a já nabízím následující rady a vítám každou další radu (nebo samozřejmě protiradu).

  1. Uložte své aktuální hodnoty do vyhrazené tabulky. NEPOUŽÍVEJTE sekvenci.
  2. Zajistěte, aby všechny procesy používaly stejný kód ke generování nových čísel tím, že jej zapouzdříte do funkce nebo procedury.
  3. Serializujte přístup ke generátoru čísel pomocí DBMS_Lock a ujistěte se, že každá série má svůj vlastní vyhrazený zámek.
  4. Podržte zámek v generátoru řad, dokud nebude transakce vytvoření entity dokončena uvolněním zámku při odevzdání
  5. Vygenerování čísla odložte na poslední možnou chvíli.
  6. Zvažte dopad neočekávané chyby po vygenerování čísla a před dokončením odevzdání – vrátí se aplikace elegantně a uvolní zámek, nebo podrží zámek na generátoru série, dokud se relace později neodpojí? Ať už se použije jakákoli metoda, pokud transakce selže, musí být sériové číslo (čísla) „vráceno do fondu“.
  7. Můžete to celé zapouzdřit do spouštěče na tabulce entity? Můžete jej zapouzdřit do tabulky nebo jiného volání rozhraní API, které vloží řádek a vložení automaticky potvrdí?

Původní článek



  1. Závažná chyba:Volání nedefinované funkce mysql_connect()

  2. SQL Jak aktualizovat SUM sloupce přes skupinu ve stejné tabulce

  3. Přidání objektu dict do postgresql

  4. Pomalý dotaz při použití ORDER BY