De tillfälliga tabellerna är ett användbart koncept som finns i de flesta SGBD, även om de ofta fungerar annorlunda.
Den här bloggen beskriver de tekniska funktionerna för den här typen av tabeller antingen i databaser PostgreSQL (version 11) eller Oracle (version 12c) med några specifika exempel. Även om syftet med dessa tabeller kan vara detsamma för alla SGBD:er, är deras detaljer, eller sättet för implementering och manipulation, helt olika.
Den här funktionen kan användas både av utvecklare eller databasadministratörer för att lagra mellanliggande resultat som kommer att behövas för vidare bearbetning för att ge bra prestandamått.
Tillfälliga tabeller i PostgreSQL
I PostgreSQL är dessa objekt endast giltiga för den aktuella sessionen:de skapas, används och släpps längs samma session:strukturen för tabellen och hanterade data är endast synliga för den aktuella sessionen, så de andra sessionerna har inte tillgång till de tillfälliga tabellerna som skapades på de andra sessionerna.
Nedan visas ett enkelt exempel för att skapa en tillfällig tabell:
CREATE TEMPORARY TABLE tt_customer
(
customer_id INTEGER
)
ON COMMIT DELETE ROWS;
De temporära tabellerna skapas i ett tillfälligt schema:pg_temp_nn och det är möjligt att skapa index på dessa tabeller:
creation index tt_cusomer_idx_1 on tt_customer(customer_id)
Eftersom dataraderna i dessa tabeller också skulle kunna raderas, är det möjligt att frigöra den upptagna lagringen genom exekvering av vaccum kommando:
VACUUM VERBOSE tt_customer
analysen kommandot kan också utföras på de tillfälliga tabellerna för att samla in statistiken:
ANALYZE VERBOSE tt_customer;
Båda kommandona kan köras för den här typen av tabeller som SQL-kommando, men autovaccum demon som kör dem verkar inte på de temporära tabellerna.
En annan viktig punkt att tänka på att den är relaterad till de permanenta och temporära tabellerna med samma namn:när det väl händer tas endast den permanenta tabellen i beaktande när den anropas med dess schema som prefix.
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)
Från föregående exempel medan den temporära tabellen existerar, hänvisar alla till kunderna hänvisar till denna tabell istället till den permanenta.
Utvecklartips för tillfälliga tabeller
Syftet med det här exemplet är att tilldela en bonus för kunder som inte har gjort inköp eller loggat in på mer än ett år, så utvecklarens script istället för att använda underfrågor i frågor som en möjlig lösning (eller användning av CTE:er) uttalande) kan använda temporära tabeller (som vanligtvis är snabbare än att använda underfrågor):
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)
DBA-tips för tillfälliga tabeller
En typisk uppgift för databasadministratörer är att rensa alla stora tabeller som innehåller data som inte längre behövs. Detta måste göras mycket snabbt och det händer ofta. Standardmetoden är att flytta dessa data till en historisk tabell i ett annat schema eller till en databas som används mindre ofta.
Så, för att utföra denna flytt, på grund av prestandaproblem kan den bästa lösningen vara att använda tillfälliga tabeller:
CREATE TEMPORARY TABLE tt_customer
(
customer_id INTEGER
)
ON COMMIT DROP;
I det här exemplet skapades den temporära tabellen med alternativet DROP, så det betyder att den kommer att tas bort i slutet av det aktuella transaktionsblocket.
Här är lite annan viktig information om PostgreSQL temporära tabeller:
- Tillfälliga tabeller tas bort automatiskt i slutet av en session eller, som presenterades i föregående exempel, i slutet av den aktuella transaktionen
- Permanenta tabeller med samma namn är inte synliga för den aktuella sessionen medan den temporära tabellen existerar, såvida de inte refereras med schemakvalificerade namn
- Alla index som skapas i en temporär tabell är också automatiskt temporära
- På COMMIT bevara rader är det standardbeteendet
- Valfritt kan GLOBAL eller LOCAL skrivas före TEMPORARY eller TEMP. Detta gör för närvarande ingen skillnad i PostgreSQL och det är utfasat
- Det autovakuum daemon kan inte komma åt dessa tabeller och kan därför inte dammsuga eller analysera tillfälliga tabeller, men som visats tidigare kan autovacuum och analyskommandona användas som SQL-kommandon.
Global Temporary Tables (GTT) i Oracle
Den här typen av tabeller är kända i Oracle-världen som en Global Temporary Table (eller GTT). Dessa objekt är beständiga i databasen och kan sammanfattas med följande egenskaper:
- Strukturen är statisk och synlig för alla användare, men dess innehåll är endast synligt för den aktuella sessionen
- Det kan skapas i ett specifikt schema (som standard kommer att ägas av användaren som utfärdar kommandot) och de är inbyggda i TEMP-tabellutrymmet
- När den har skapats i databasen kan den inte skapas igen i varje session, men data som hanteras av en session är inte synliga för de andra sessionerna
- Det är möjligt att skapa index och generera statistik
- Eftersom strukturen för dessa tabeller också är definierad i databasen är det inte möjligt att tilldela dess namn till en permanent tabell (i Oracle kan två objekt inte ha samma namn även från olika typer)
- Generera inte för många redo-loggar och ångra-overheaden är också mindre jämfört med en permanent tabell (endast av dessa skäl är det snabbare att använda GTT) för alla versioner före 12c. Från 12c-versionen finns det ett koncept med temporär ångra, vilket gör att ångra för en GTT kan skrivas till den tillfälliga tabellutrymmet, vilket minskar ångra och gör om.
Efter samma exempel som presenteras i PostgreSQL, är skapandet av en GTT ganska liknande:
CREATE GLOBAL TEMPORARY TABLE tt_customer
(
customer_id NUMBER
)
ON COMMIT DELETE ROWS;
Det är också möjligt att skapa index.
creation index tt_cusomer_idx_1 on tt_customer(customer_id)
Före Oracle 12c hade genereringen av statistik för globala temporära tabeller ett beteende på ett globalt sätt:statistiken som genererades i en specifik session för en specifik GTT var synlig och användes för de andra sessionerna (endast statistik inte data!), dock, från version 12c är det möjligt för varje session att generera sin egen statistik.
Först och främst är det nödvändigt att ställa in inställningen global_temp_table_stats till session :
exec dbms_stats.set_table_prefs(USER,’TT_CUSTOMER’,’GLOBAL_TEMP_TABLE_STATS’,’SESSION’);
och sedan generering av statistik:
exec dbms_stats.gather_table_stats(USER,’TT_CUSTOMER’);
Den befintliga globala temporära tabellen kan kontrolleras genom att köra följande fråga:
select table_name from all_tables where temporary = 'Y';
Utvecklartips för globala tillfälliga tabeller (GTT)
Efter exemplet på PostgreSQL-sektionen:att tilldela en bonus för kunder som inte har gjort inköp eller loggat in på mer än ett år, har användningen av globala temporära tabeller i Oracle samma mål som i PostgreSQL:att uppnå bättre prestanda antingen i resursanvändning eller körhastighet.
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>
Som standard i Oracle startar ett SQL/PLSQL-block/-sats implicit en transaktion.
DBA-tips för globala tillfälliga tabeller (GTT)
Som uttalandet släpp existerar inte för globala temporära tabeller kommandot för att skapa tabellen är detsamma som den föregående:
CREATE GLOBAL TEMPORARY TABLE tt_customer
(
customer_id NUMBER
)
ON COMMIT DELETE ROWS;
Motsvarande kodavsnitt i Oracle för att rensa kunden tabellen är det följande:
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.
pg_global_temp_tables-biblioteket
Som nämnts ovan kan de temporära tabellerna i PostgreSQL inte anropas med hjälp av notationen schema.table , så pg_global_temp_tables-biblioteket (det finns några liknande bibliotek tillgängliga på github) det är en lösning som är mycket användbar för att användas i databasmigreringar från Oracle till PostgreSQL.
För att behålla Oracle-notationen schema.temporary_table i frågor eller lagrade procedurer:
SELECT c.id,c.nam
FROM web_app.tt_customers tc,
Web_app.customers c
WHERE c.id = tc.id
Det tillåter att förbli de tillfälliga tabellerna över koden med schemanotationen.
I grund och botten består den av en vy:web_app.tt_customers skapas under schemat som den ska ha den temporära tabellen på och den här vyn kommer att fråga den temporära tabellen tt_customers genom en funktion som heter web_app.select_tt_customers :
CREATE OR REPLACE VIEW WEB_APP.TT_CUSTOMERS AS
SELECT * FROM WEB_APP.SELECT_TT_CUSTOMERS();
Denna funktion returnerar innehållet i den temporära tabellen:
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;
Sammanfattning
De temporära tabellerna används huvudsakligen för att lagra mellanliggande resultat och därmed undvika komplex och tung beräkning,
Därefter listas några egenskaper hos temporära tabeller antingen i PostgreSQL eller Oracle:
- Den kan användas på visning
- Den kan använda kommandot TRUNCATE
- Det går inte att partitionera
- Begränsningen för främmande nyckel på temporära tabeller är inte tillåten
- Denna typ av tabeller är ett alternativ för CTE:er (Common Table Expressions) även kända för Oracle-proffs som WITH-klausul
- När det gäller säkerhet och integritet är dessa tabeller en värdefull tillgång eftersom data endast är synliga för en aktuell session
- De temporära tabellerna släpps automatiskt (i PostgreSQL) eller raderas (i Oracle) när sessionen/transaktionen avslutas.
För de temporära tabellerna i PostgreSQL är det tillrådligt att inte använda samma namn på en permanent tabell i en temporär tabell. På Oracle-sidan är det en god praxis att generera statistik för sessionerna som inkluderar en betydande mängd data i GTT för att tvinga den kostnadsbaserade optimeraren (CBO) att välja den bästa planen för de frågor som använder den här typen av tabeller .