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

Porovnání dočasných tabulek pro PostgreSQL a Oracle GTT

Dočasné tabulky jsou užitečným konceptem přítomným ve většině SGBD, i když často fungují odlišně.

Tento blog popisuje technické funkce pro tento druh tabulek v databázích PostgreSQL (verze 11) nebo Oracle (verze 12c) s několika konkrétními příklady. Přestože účel těchto tabulek by mohl být pro všechny SGBD stejný, jejich specifika nebo způsob implementace a manipulace jsou zcela odlišné.

Tuto funkci mohou používat vývojáři nebo správci databází k ukládání mezivýsledků, které budou potřeba pro další zpracování, aby bylo možné poskytnout dobré metriky výkonu.

Dočasné tabulky v PostgreSQL

V PostgreSQL jsou tyto objekty platné pouze pro aktuální relaci:jsou vytvořeny, použity a zrušeny během stejné relace:struktura tabulky a spravovaná data jsou viditelná pouze pro aktuální relaci, takže ostatní relace nemají přístup k dočasné tabulky vytvořené v jiných relacích.

Níže je uveden jednoduchý příklad vytvoření dočasné tabulky:

CREATE TEMPORARY TABLE tt_customer
(
     customer_id INTEGER
)
ON COMMIT DELETE ROWS;

Dočasné tabulky jsou vytvořeny v dočasném schématu:pg_temp_nn a je možné vytvářet indexy na těchto tabulkách:

creation index  tt_cusomer_idx_1 on tt_customer(customer_id)

Vzhledem k tomu, že datové řádky v těchto tabulkách lze také smazat, je možné uvolnit obsazené úložiště provedením vakuum příkaz:

VACUUM VERBOSE tt_customer

Analýza příkaz lze také provést na dočasných tabulkách za účelem shromáždění statistik:

ANALYZE VERBOSE tt_customer;

Oba příkazy lze pro tento typ tabulky provést jako příkaz SQL, nicméně autovaccum démon, který je spouští, nepůsobí na dočasné tabulky.

Další důležitý bod, který je třeba vzít v úvahu, souvisí s trvalými a dočasnými tabulkami se stejným názvem:jakmile k tomu dojde, vezme se v úvahu pouze trvalá tabulka, když je volána s jejím schématem jako prefixem.

web_db=# BEGIN TRANSACTION;
BEGIN
web_db=# SELECT COUNT(*) FROM customers;
  count  
---------
 1030056
(1 row)

web_db=# CREATE TEMPORARY TABLE customers(
web_db(#   id INTEGER
web_db(# )
web_db-# ON COMMIT PRESERVE ROWS;
CREATE TABLE
web_db=# INSERT INTO customers(id) VALUES(1023);
INSERT 0 1
web_db=# SELECT COUNT(*) FROM customers;
 count 
-------
     1
(1 row)
web_db=# \dt *customers*
                  List of relations
  Schema   |         Name         | Type  |  Owner   
-----------+----------------------+-------+----------
 pg_temp_5 | customers            | table | postgres
 web_app   | customers            | table | postgres
 web_app   | customers_historical | table | postgres
(3 rows)
web_db=# DROP TABLE customers;
DROP TABLE
web_db=# \dt *customers*
                 List of relations
 Schema  |         Name         | Type  |  Owner   
---------+----------------------+-------+----------
 web_app | customers            | table | postgres
 web_app | customers_historical | table | postgres
(2 rows)
web_db=# SELECT COUNT(*) FROM web_app.customers; 
  count  
---------
 1030056
(1 row)
web_db=# SELECT COUNT(*) FROM customers; 
  count  
---------
 1030056
(1 row)

Z předchozího příkladu, zatímco dočasná tabulka existuje, všechny odkazy na zákazníky odkazuje na tuto tabulku místo na trvalou.

Tipy pro vývojáře pro dočasné tabulky

Účelem tohoto příkladu je přiřadit bonus pro zákazníky, kteří nenakoupili nebo se nepřihlásili déle než rok, takže skript vývojáře místo toho použít poddotazy v dotazech jako možné řešení (nebo použití CTE příkaz) může používat dočasné tabulky (obvykle je to rychlejší než použití poddotazů):

web_db=# BEGIN TRANSACTION;
BEGIN
web_db=# CREATE TEMPORARY TABLE tt_customers(
web_db(#   id INTEGER
web_db(# )
web_db-# ON COMMIT DELETE ROWS;
CREATE TABLE
web_db=# SELECT COUNT(*) FROM tt_customers;
 count 
-------
     0
(1 row)
web_db=# INSERT INTO tt_customers(id)
web_db-# SELECT customer_id
web_db-#   FROM web_app.orders
web_db-# WHERE order_dt <= NOW()-INTERVAL '6 MONTH';
INSERT 0 1030056
web_db=# SELECT COUNT(*) FROM tt_customers;
  count  
---------
 1030056
(1 row)
web_db=# DELETE FROM tt_customers c
web_db-# WHERE EXISTS(SELECT 1 
web_db(#                FROM web_app.users u JOIN web_app.login l 
web_db(#                       ON (l.user_id=u.user_id) 
web_db(#               WHERE u.customer_id=c.id 
web_db(#                 AND l.login_dt > NOW()-INTERVAL '6 MONTH'
web_db(#                 );
DELETE 194637
web_db=# SELECT COUNT(*) FROM tt_customers;
 count  
--------
 835419
(1 row)
web_db=# UPDATE web_app.customers as c SET BONUS=5
web_db-# FROM tt_customers t
web_db-# WHERE t.id = c.id;
UPDATE 835419
web_db=# SELECT COUNT(*) FROM tt_customers;
 count  
--------
 835419
(1 row)
web_db=# COMMIT TRANSACTION;
COMMIT
web_db=# SELECT COUNT(*) FROM tt_customers;
 count 
-------
     0
(1 row)

Tipy DBA pro dočasné tabulky

Typickým úkolem administrátorů databází je vyčistit všechny velké tabulky, které obsahují data, která již nejsou potřeba. To je potřeba dokončit velmi rychle a stává se to často. Standardním přístupem je přesunout tato data do historické tabulky v jiném schématu nebo do databáze, ke které se přistupuje méně často.

Aby bylo možné provést tento přesun, kvůli problémům s výkonem by nejlepším řešením mohlo být použití dočasných tabulek:

CREATE TEMPORARY TABLE tt_customer
(
     customer_id INTEGER
)
ON COMMIT DROP;

V tomto příkladu byla dočasná tabulka vytvořena s možností DROP, takže to znamená, že bude zrušena na konci aktuálního bloku transakce.

Zde jsou některé další důležité informace o dočasných tabulkách PostgreSQL:

  • Dočasné tabulky jsou automaticky zrušeny na konci relace nebo, jak je uvedeno v předchozím příkladu, na konci aktuální transakce
  • Stálé tabulky se stejným názvem nejsou viditelné pro aktuální relaci, dokud dočasná tabulka existuje, pokud na ně neodkazují názvy kvalifikované pro schéma
  • Jakékoli indexy vytvořené v dočasné tabulce jsou také automaticky dočasné
  • PO COMMIT zachovat řádky je to výchozí chování
  • Volitelně lze před TEMPORARY nebo TEMP zapsat GLOBAL nebo LOCAL. To v současné době nečiní žádný rozdíl v PostgreSQL a je zastaralé
  • autovakuum démon nemůže přistupovat k těmto tabulkám, a proto nemůže vysávat nebo analyzovat dočasné tabulky, nicméně, jak bylo ukázáno dříve, příkazy autovacuum a analyzovat lze použít jako příkazy SQL.

Globální dočasné tabulky (GTT) v Oracle

Tento druh tabulek je ve světě Oracle známý jako Global Temporary Table (nebo GTT). Tyto objekty jsou v databázi trvalé a lze je shrnout do následujících charakteristik:

  • Struktura je statická a viditelná pro všechny uživatele, její obsah je však viditelný pouze pro aktuální relaci
  • Lze je vytvořit ve specifickém schématu (ve výchozím nastavení bude vlastnictvím uživatele, který příkaz vydal) a jsou zabudovány v tabulkovém prostoru TEMP
  • Jakmile je databáze vytvořena, nelze ji znovu vytvořit v každé relaci, avšak data spravovaná relací nejsou viditelná pro ostatní relace.
  • Je možné vytvářet indexy a generovat statistiky
  • Vzhledem k tomu, že struktura těchto tabulek je definována i v databázi, není možné přiřadit její název trvalé tabulce (v Oracle nemohou mít dva objekty stejné jméno ani z různých typů)
  • Negenerujte příliš mnoho opakovaných protokolů a režii zpět je také méně ve srovnání s trvalou tabulkou (pouze z těchto důvodů je použití GTT rychlejší) pro všechny verze před 12c. Od verze 12c existuje koncept dočasného vrácení zpět, který umožňuje zapsání zpět pro GTT do dočasného tabulkového prostoru, čímž se omezuje zpětný chod a opakování.

Podle stejného příkladu prezentovaného v PostgreSQL je vytvoření GTT docela podobné:

CREATE GLOBAL TEMPORARY TABLE tt_customer
(
     customer_id NUMBER
)
ON COMMIT DELETE ROWS;

Je také možné vytvářet indexy.

creation index  tt_cusomer_idx_1 on tt_customer(customer_id)

Před Oracle 12c se generování statistik pro globální dočasné tabulky chovalo globálním způsobem:statistiky generované v konkrétní relaci pro konkrétní GTT byly viditelné a používané pro ostatní relace (pouze statistiky, nikoli data!), nicméně, od verze 12c je možné pro každou relaci generovat vlastní statistiky.

Nejprve je nutné nastavit předvolbu global_temp_table_stats do relace :

exec dbms_stats.set_table_prefs(USER,’TT_CUSTOMER’,’GLOBAL_TEMP_TABLE_STATS’,’SESSION’);

a poté generování statistik:

exec dbms_stats.gather_table_stats(USER,’TT_CUSTOMER’);

Existující globální dočasnou tabulku lze zkontrolovat provedením následujícího dotazu:

select table_name from all_tables where temporary = 'Y';

Tipy pro vývojáře pro globální dočasné tabulky (GTT)

Podle příkladu v sekci PostgreSQL:pro přidělení bonusu pro zákazníky, kteří nenakoupili nebo se nepřihlásili déle než rok, má použití globálních dočasných tabulek v Oracle stejný cíl jako v PostgreSQL:dosáhnout lepšího výkonu buď v využití zdroje nebo rychlost provádění.

SQL> SELECT COUNT(*) FROM tt_customers;
  COUNT(*)
----------
         0
SQL>
SQL> INSERT INTO tt_customers(id)
  2  SELECT customer_id
  3    FROM orders
  4  WHERE order_dt <= ADD_MONTHS(SYSDATE,-6);
1030056 rows created.
SQL>
SQL> SELECT COUNT(*) FROM tt_customers;
  COUNT(*)
----------
   1030056
SQL>
SQL> DELETE FROM tt_customers c
  2  WHERE EXISTS(SELECT 1
  3                 FROM users u JOIN login l
  4                        ON (l.user_id=u.user_id)
  5                WHERE u.customer_id=c.id
  6                  AND l.login_dt > ADD_MONTHS(SYSDATE,-6)
  7                  );
194637 rows deleted.
SQL>
SQL> SELECT COUNT(*) FROM tt_customers;
  COUNT(*)
----------
    835419
SQL>
SQL> UPDATE CUSTOMERS c SET BONUS=5
  2  WHERE EXISTS(SELECT 1 FROM tt_customers tc WHERE tc.id=c.id);
835419 rows updated.
SQL>
SQL> SELECT COUNT(*) FROM tt_customers;
  COUNT(*)
----------
    835419
SQL>
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT COUNT(*) FROM tt_customers;
  COUNT(*)
----------
         0

SQL>

Ve výchozím nastavení v Oracle SQL/PLSQL blok/příkaz spouští implicitně transakci.

Tipy DBA pro globální dočasné tabulky (GTT)

Jako příkaz klesnout pro globální dočasné tabulky neexistuje příkaz k vytvoření tabulky je stejný jako předchozí:

CREATE GLOBAL TEMPORARY TABLE tt_customer
(
     customer_id NUMBER
)
ON COMMIT DELETE ROWS;

Ekvivalentní úryvek kódu v Oracle k vyčištění zákazníka tabulka je následující:

SQL> INSERT INTO tt_customers(id)
  2  SELECT l.user_id
  3    FROM users u JOIN login l
  4           ON (l.user_id=u.user_id)
  5   WHERE l.login_dt < ADD_MONTHS(SYSDATE,-12);
194637 rows created.
SQL>
SQL> INSERT INTO tt_customers(id)
  2  SELECT user_id
  3    FROM web_deactive;
2143 rows created.
SQL>
SQL> INSERT INTO tt_customers(id)
  2  SELECT user_id
  3    FROM web_black_list;
4234 rows created.
SQL>
SQL> INSERT INTO customers_historical(id,name)
  2  SELECT c.id,c.name
  3  FROM customers c,
  4  tt_customers tc
  5  WHERE tc.id = c.id;
201014 rows created.
SQL>
SQL> DELETE FROM customers c
  2  WHERE EXISTS (SELECT 1 FROM  tt_customers tc WHERE tc.id = c.id );
201014 rows deleted.

Knihovna pg_global_temp_tables

Jak bylo uvedeno výše, dočasné tabulky v PostgreSQL nelze vyvolat pomocí zápisu schema.table , takže knihovna pg_global_temp_tables (na githubu je k dispozici několik podobných knihoven), je to velmi užitečné řešení, které lze použít při migracích databází z Oracle na PostgreSQL.

Aby byla zachována notace Oracle schema.temporary_table v dotazech nebo uložených procedurách:

SELECT c.id,c.nam
    FROM web_app.tt_customers tc,
                 Web_app.customers c
    WHERE c.id = tc.id

Umožňuje ponechat dočasné tabulky nad kódem se zápisem schématu.

V podstatě se skládá z pohledu:web_app.tt_customers vytvořen pod schématem, na kterém má mít dočasnou tabulku, a tento pohled bude dotazovat dočasnou tabulku tt_customers prostřednictvím funkce nazvané web_app.select_tt_customers :

CREATE OR REPLACE VIEW WEB_APP.TT_CUSTOMERS AS 
  SELECT * FROM WEB_APP.SELECT_TT_CUSTOMERS();

Tato funkce vrací obsah dočasné tabulky:

CREATE OR REPLACE FUNCTION WEB_APP.SELECT_TT_CUSTOMERS() RETURNS TABLE(ID INR, NAME VARCHAR) AS $$
BEGIN
    CREATE TEMPORARY TABLE IF NOT EXISTS TT_CUSTOMERS(ID INT, NAME) ON COMMIT DROP;
    RETURN QUERY SELECT * FROM TT_CUSTOMERS;
END;
$$ LANGUAGE PLPGSQL;  

Shrnutí

Dočasné tabulky se používají v podstatě k ukládání mezivýsledků, a tak se vyhnou složitým a náročným výpočtům,

Dále jsou uvedeny některé charakteristiky dočasných tabulek v PostgreSQL nebo Oracle:

  • Lze jej použít na zobrazení
  • Může používat příkaz TRUNCATE
  • Nelze jej rozdělit
  • Omezení cizího klíče u dočasných tabulek není povoleno
  • Tento druh tabulek je alternativou pro CTE (Common Table Expressions), které odborníci na Oracle označují také jako klauzule WITH
  • Z hlediska zabezpečení a ochrany soukromí jsou tyto tabulky cenným přínosem, protože data jsou viditelná pouze pro aktuální relaci.
  • Po skončení relace/transakce jsou dočasné tabulky automaticky zrušeny (v PostgreSQL) nebo smazány (v Oracle).

Pro dočasné tabulky v PostgreSQL je vhodné nepoužívat stejný název trvalé tabulky v dočasné tabulce. Na straně Oracle je dobrým zvykem generovat statistiky pro relace, které obsahují značný objem dat v GTT, aby bylo možné přinutit Cost-Based Optimizer (CBO) vybrat nejlepší plán pro dotazy, které používají tento druh tabulek. .


  1. Jak interpretovat hodnotu txid_current() PosgreSQL

  2. Jak změnit formát data a času v T-SQL

  3. Odesílání typu NULL při aktualizaci více řádků

  4. 2017 @ Somenines:Oslava příběhů našich zákazníků