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

Jak předat sadu řádků z jedné funkce do druhé?

Tabulkové funkce

Provádím velmi rychlé, komplexní migrace databází, abych se živil, pomocí SQL jako jazyka klienta i serveru (nepoužívá se žádný jiný jazyk), vše běží na straně serveru, kde se kód zřídka objevuje z databázového stroje. Funkce tabulek hrají v mé práci VELKOU roli . Nepoužívám "kurzory", protože jsou příliš pomalé na to, aby splnily mé požadavky na výkon, a vše, co dělám, je orientováno na sadu výsledků. Tabulkové funkce mi nesmírně pomohly při úplném odstranění použití kurzorů, dosažení velmi vysoké rychlosti a dramaticky přispěly ke snížení objemu kódu a zlepšení jednoduchosti.

Stručně řečeno, použijete dotaz který odkazuje na dvě (nebo více) tabulkových funkcí pro předávání dat z jedné tabulkové funkce do další. Sada výsledků výběrového dotazu, která volá tabulkové funkce, slouží jako kanál pro předávání dat z jedné tabulkové funkce do další. Na platformě / verzi DB2, na které pracuji, a na základě rychlého pohledu do manuálu 9.1 Postgres se zdá, že totéž platí i tam, můžete předat pouze jeden řádek hodnot sloupců jako vstup do libovolného volání funkcí tabulky, jak jsi zjistil. Vzhledem k tomu, že k volání tabulkové funkce dochází uprostřed zpracování sady výsledků dotazu, dosáhnete stejného účinku předáním celé sady výsledků každému volání tabulkové funkce, i když v instalaci databázového stroje jsou data předána pro každou funkci tabulky vždy pouze jeden řádek.

Tabulkové funkce přijímají jeden řádek vstupních sloupců a vracejí jednu sadu výsledků zpět do volajícího dotazu (tj. select), který funkci vyvolal. Sloupce sady výsledků předané zpět z tabulkové funkce se stanou součástí sady výsledků volajícího dotazu, a jsou proto dostupné jako vstup pro další tabulkovou funkci , odkazovaný později ve stejném dotazu, obvykle jako následné spojení. Sloupce výsledků první tabulkové funkce jsou přiváděny jako vstup (po jednom řádku) do druhé tabulkové funkce, která vrací své sloupce sady výsledků do sady výsledků volajícího dotazu. První i druhý sloupec sady výsledků tabulkové funkce jsou nyní součástí sady výsledků volajícího dotazu a jsou nyní dostupné jako vstup (po jednom řádku) pro třetí tabulkovou funkci. Každé volání tabulkové funkce rozšiřuje sadu výsledků volajícího dotazu o sloupce, které vrací. To může pokračovat, dokud nezačnete narážet na limity šířky sady výsledků, která se pravděpodobně liší od jednoho databázového stroje k dalšímu.

Zvažte tento příklad (který nemusí odpovídat požadavkům na syntaxi nebo schopnostem Postgresu, když pracuji na DB2). Toto je jeden z mnoha návrhových vzorů, ve kterých používám tabulkové funkce, je jedním z těch jednodušších, který je podle mého názoru velmi názorný, a předpokládám, že bude mít širokou přitažlivost pokud tabulkové funkce byly široce používány (podle mých znalostí nejsou, ale myslím, že si zaslouží více pozornosti, než se jim dostává).

V tomto příkladu jsou používané tabulkové funkce:VALIDATE_TODAYS_ORDER_BATCH, POST_TODAYS_ORDER_BATCH a DATA_WAREHOUSE_TODAYS_ORDER_BATCH. Ve verzi DB2, na které pracuji, zabalíte tabulkovou funkci do "TABLE( zde umístěte volání a parametry tabulkové funkce )", ale na základě rychlého pohledu do příručky Postgres se zdá, že vynecháváte obal "TABLE( )".

create table TODAYS_ORDER_PROCESSING_EXCEPTIONS as (

select      TODAYS_ORDER_BATCH.*
           ,VALIDATION_RESULT.ROW_VALID
           ,POST_RESULT.ROW_POSTED
           ,WAREHOUSE_RESULT.ROW_WAREHOUSED

from        TODAYS_ORDER_BATCH

cross join  VALIDATE_TODAYS_ORDER_BATCH ( ORDER_NUMBER, [either pass the remainder of the order columns or fetch them in the function]  ) 
              as VALIDATION_RESULT ( ROW_VALID )  --example: 1/0 true/false Boolean returned

left join   POST_TODAYS_ORDER_BATCH ( ORDER_NUMBER, [either pass the remainder of the order columns or fetch them in the function] )
              as POST_RESULT ( ROW_POSTED )  --example: 1/0 true/false Boolean returned
      on    ROW_VALIDATED = '1'

left join   DATA_WAREHOUSE_TODAYS_ORDER_BATCH ( ORDER_NUMBER, [either pass the remainder of the order columns or fetch them in the function] )
              as WAREHOUSE_RESULT ( ROW_WAREHOUSED )  --example: 1/0 true/false Boolean returned
      on    ROW_POSTED = '1'

where       coalesce( ROW_VALID,      '0' ) = '0'   --Capture only exceptions and unprocessed work.  
      or    coalesce( ROW_POSTED,     '0' ) = '0'   --Or, you can flip the logic to capture only successful rows.
      or    coalesce( ROW_WAREHOUSED, '0' ) = '0'

) with data
  1. Pokud tabulka TODAYS_ORDER_BATCH obsahuje 1 000 000 řádků, bude VALIDATE_TODAYS_ORDER_BATCH vyvolána 1 000 000krát, jednou pro každý řádek.
  2. Pokud v rámci VALIDATE_TODAYS_ORDER_BATCH projde ověřením 900 000 řádků, bude POST_TODAYS_ORDER_BATCH vyvoláno 900 000krát.
  3. Pokud se úspěšně odešle pouze 850 000 řádků, pak VALIDATE_TODAYS_ORDER_BATCH potřebuje uzavřít některé mezery LOL a DATA_WAREHOUSE_TODAYS_ORDER_BATCH bude voláno 850 000krát.
  4. Pokud se do datového skladu úspěšně dostalo 850 000 řádků (tj. nebyly vygenerovány žádné další výjimky), tabulka TODAYS_ORDER_PROCESSING_EXCEPTIONS bude naplněna 1 000 000 - 850 000 =150 000 řádky výjimek.

Volání tabulkových funkcí v tomto příkladu vracejí pouze jeden sloupec, ale mohou vracet mnoho sloupců. Například tabulková funkce ověřující řádek objednávky může vrátit důvod, proč se ověření objednávky nezdařilo.

V tomto návrhu je prakticky veškeré chvění mezi HLL a databází eliminováno, protože žadatel HLL žádá databázi, aby zpracovala celou dávku v JEDNOM požadavku. To má za následek snížení milionů požadavků SQL do databáze, OBROVSKÉ odstranění milionů volání procedur nebo metod HLL a ve výsledku poskytuje OBROVSKÉ vylepšení běhového prostředí. Naproti tomu starší kód, který často zpracovává jeden řádek najednou, by obvykle odeslal 1 000 000 požadavků na načtení SQL, 1 na každý řádek v TODAYS_ORDER_BATCH, plus alespoň 1 000 000 požadavků HLL a/nebo SQL pro účely ověření, plus alespoň 1 000 000 HLL a /nebo požadavky SQL pro účely zaúčtování plus 1 000 000 požadavků HLL a/nebo SQL pro odeslání objednávky do datového skladu. Je samozřejmé, že pomocí tohoto návrhu tabulkové funkce jsou uvnitř tabulkových funkcí odesílány požadavky SQL do databáze, ale když databáze požaduje požadavky na sebe (tj. z tabulkové funkce), jsou požadavky SQL obsluhovány mnohem rychleji (zejména ve srovnání s starší scénář, kdy žadatel HLL provádí zpracování jednoho řádku ze vzdáleného systému, v nejhorším případě přes WAN - OMG to prosím nedělejte).

Pokud použijete tabulkovou funkci k "načtení sady výsledků" a poté tuto sadu výsledků připojíte k jiným tabulkám, můžete snadno narazit na problémy s výkonem. V takovém případě nemůže optimalizátor SQL předpovědět, jaká sada řádků bude vrácena z tabulkové funkce, a proto nemůže optimalizovat spojení s následujícími tabulkami. Z toho důvodu je zřídka používám pro načítání sady výsledků, pokud nevím, že sada výsledků bude mít velmi malý počet řádků, takže nezpůsobí problém s výkonem nebo se nepotřebuji připojit k dalším tabulkám.

Podle mého názoru je jedním z důvodů, proč jsou tabulkové funkce nedostatečně využívány, to, že jsou často vnímány pouze jako nástroj k načtení sady výsledků, který často funguje špatně, takže jsou odepsány jako „špatný“ nástroj k použití.

Tabulkové funkce jsou nesmírně užitečné pro přenesení více funkcí na server, pro eliminaci většiny chat mezi databázovým serverem a programy na vzdálených systémech a dokonce pro odstranění chatování mezi databázovým serverem a externími programy na stejném serveru. Dokonce i chatování mezi programy na stejném serveru přináší více režie, než si mnoho lidí uvědomuje, a mnoho z toho je zbytečné. Srdcem tabulkových funkcí je jejich použití k provádění akcí v rámci zpracování sady výsledků.

Existují pokročilejší návrhové vzory pro použití tabulkových funkcí, které staví na výše uvedeném vzoru, kde můžete ještě dále maximalizovat zpracování výsledné sady, ale tento příspěvek je pro většinu již hodně k vstřebání.




  1. mysqlworkbench hlásí chybu verze při exportu databáze

  2. Jak RLIKE funguje v MariaDB

  3. Jak ignorovat parametr v uložené proceduře, pokud je jeho hodnota null

  4. DATEDIFF() vs DATEDIFF_BIG() v SQL Server:Jaký je rozdíl?