Die temporären Tabellen sind ein nützliches Konzept, das in den meisten SGBDs vorhanden ist, auch wenn sie oft anders funktionieren.
Dieser Blog beschreibt die technischen Funktionen für diese Art von Tabellen entweder in PostgreSQL- (Version 11) oder Oracle-Datenbanken (Version 12c) mit einigen spezifischen Beispielen. Obwohl der Zweck dieser Tabellen für alle SGBDs gleich sein könnte, sind ihre Besonderheiten oder die Art und Weise der Implementierung und Bearbeitung völlig unterschiedlich.
Diese Funktion könnte sowohl von Entwicklern als auch von Datenbankadministratoren verwendet werden, um Zwischenergebnisse zu speichern, die für die weitere Verarbeitung benötigt werden, um gute Leistungsmetriken bereitzustellen.
Temporäre Tabellen in PostgreSQL
In PostgreSQL sind diese Objekte nur für die aktuelle Sitzung gültig:Sie werden in derselben Sitzung erstellt, verwendet und gelöscht:Die Struktur der Tabelle und die verwalteten Daten sind nur für die aktuelle Sitzung sichtbar, daher haben die anderen Sitzungen keinen Zugriff darauf die in den anderen Sitzungen erstellten temporären Tabellen.
Unten sehen Sie ein einfaches Beispiel zum Erstellen einer temporären Tabelle:
CREATE TEMPORARY TABLE tt_customer
(
customer_id INTEGER
)
ON COMMIT DELETE ROWS;
Die temporären Tabellen werden in einem temporären Schema erstellt:pg_temp_nn und es ist möglich, Indizes für diese Tabellen zu erstellen:
creation index tt_cusomer_idx_1 on tt_customer(customer_id)
Da die Datenzeilen auf diesen Tabellen auch gelöscht werden könnten, ist es möglich, den belegten Speicherplatz durch die Ausführung von vaccum freizugeben Befehl:
VACUUM VERBOSE tt_customer
Die Analyse Befehl kann auch auf den temporären Tabellen ausgeführt werden, um die Statistiken zu sammeln:
ANALYZE VERBOSE tt_customer;
Beide Befehle können für diese Art von Tabelle als SQL-Befehl ausgeführt werden, jedoch der autovaccum Daemon, der sie ausführt, wirkt nicht auf die temporären Tabellen.
Ein weiterer wichtiger Punkt, der zu beachten ist, bezieht sich auf die permanenten und temporären Tabellen mit demselben Namen:Sobald dies passiert, wird die permanente Tabelle nur berücksichtigt, wenn sie mit ihrem Schema als Präfix aufgerufen wird.
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)
Aus dem vorherigen Beispiel, solange die temporäre Tabelle existiert, beziehen sich alle auf die Kunden bezieht sich auf diese Tabelle statt auf die permanente.
Entwicklertipps für temporäre Tabellen
Der Zweck dieses Beispiels ist es, den Kunden, die länger als ein Jahr nicht eingekauft oder sich nicht angemeldet haben, einen Bonus zuzuweisen, sodass das Skript des Entwicklers stattdessen Unterabfragen in Abfragen als mögliche Lösung verwendet (oder die Verwendung von CTEs -Anweisung) kann temporäre Tabellen verwenden (das ist normalerweise schneller als die Verwendung von Unterabfragen):
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-Tipps für temporäre Tabellen
Eine typische Aufgabe für Datenbankadministratoren besteht darin, große Tabellen zu löschen, die Daten enthalten, die nicht mehr benötigt werden. Dies muss sehr schnell erledigt werden und kommt oft vor. Der Standardansatz besteht darin, diese Daten in eine historische Tabelle in einem anderen Schema oder in eine Datenbank zu verschieben, auf die seltener zugegriffen wird.
Um diese Verschiebung durchzuführen, könnte die beste Lösung aufgrund von Leistungsproblemen die Verwendung temporärer Tabellen sein:
CREATE TEMPORARY TABLE tt_customer
(
customer_id INTEGER
)
ON COMMIT DROP;
In diesem Beispiel wurde die temporäre Tabelle mit der Option DROP erstellt, was bedeutet, dass sie am Ende des aktuellen Transaktionsblocks gelöscht wird.
Hier sind einige weitere wichtige Informationen zu temporären PostgreSQL-Tabellen:
- Temporäre Tabellen werden am Ende einer Sitzung oder, wie im vorherigen Beispiel dargestellt, am Ende der aktuellen Transaktion automatisch gelöscht
- Permanente Tabellen mit demselben Namen sind für die aktuelle Sitzung nicht sichtbar, solange die temporäre Tabelle existiert, es sei denn, sie werden mit Schema-qualifizierten Namen referenziert
- Alle Indizes, die für eine temporäre Tabelle erstellt wurden, sind automatisch ebenfalls temporär
- ON COMMIT Zeilen beibehalten ist das Standardverhalten
- Optional kann GLOBAL oder LOCAL vor TEMPORARY oder TEMP geschrieben werden. Dies macht derzeit keinen Unterschied in PostgreSQL und ist veraltet
- Das Autovakuum Daemon kann nicht auf diese Tabellen zugreifen und kann daher temporäre Tabellen nicht leeren oder analysieren, aber wie zuvor gezeigt, können die Befehle autovacuum und analyze als SQL-Befehle verwendet werden.
Globale temporäre Tabellen (GTT) in Oracle
Diese Art von Tabellen ist in der Oracle-Welt als Global Temporary Table (oder GTT) bekannt. Diese Objekte sind in der Datenbank persistent und können durch die folgenden Merkmale zusammengefasst werden:
- Die Struktur ist statisch und für alle Benutzer sichtbar, ihr Inhalt ist jedoch nur für die aktuelle Sitzung sichtbar
- Sie können in einem bestimmten Schema erstellt werden (standardmäßig gehören sie dem Benutzer, der den Befehl ausgibt) und sie werden im TEMP-Tablespace erstellt
- Einmal in der Datenbank erstellt, kann sie nicht in jeder Sitzung erneut erstellt werden, jedoch sind die von einer Sitzung verwalteten Daten für die anderen Sitzungen nicht sichtbar
- Es ist möglich, Indizes zu erstellen und Statistiken zu erstellen
- Da die Struktur dieser Tabellen auch in der Datenbank definiert ist, ist es nicht möglich, ihren Namen einer permanenten Tabelle zuzuordnen (in Oracle können zwei Objekte nicht denselben Namen haben, auch nicht von unterschiedlichen Typen)
- Generieren Sie nicht zu viele Redo-Logs und der Undo-Overhead ist auch geringer im Vergleich zu einer permanenten Tabelle (nur aus diesen Gründen ist die Verwendung von GTT schneller) für alle Versionen vor 12c. Ab der 12c-Version gibt es ein Konzept des temporären Rückgängigmachens, das es ermöglicht, das Rückgängigmachen für eine GTT in den temporären Tablespace zu schreiben, wodurch Rückgängigmachen und Wiederherstellen reduziert werden.
Nach dem gleichen Beispiel in PostgreSQL ist die Erstellung einer GTT ziemlich ähnlich:
CREATE GLOBAL TEMPORARY TABLE tt_customer
(
customer_id NUMBER
)
ON COMMIT DELETE ROWS;
Auch die Erstellung von Indizes ist möglich.
creation index tt_cusomer_idx_1 on tt_customer(customer_id)
Vor Oracle 12c hatte die Generierung von Statistiken für globale temporäre Tabellen ein globales Verhalten:Die Statistiken, die in einer bestimmten Sitzung für eine bestimmte GTT generiert wurden, waren sichtbar und wurden für die anderen Sitzungen verwendet (nur Statistiken, nicht die Daten!), jedoch ab Version 12c ist es möglich für jede Session eigene Statistiken zu erstellen.
Zunächst muss die Einstellung global_temp_table_stats gesetzt werden zu Sitzung :
exec dbms_stats.set_table_prefs(USER,’TT_CUSTOMER’,’GLOBAL_TEMP_TABLE_STATS’,’SESSION’);
und dann die Generierung von Statistiken:
exec dbms_stats.gather_table_stats(USER,’TT_CUSTOMER’);
Die vorhandene globale temporäre Tabelle könnte durch die Ausführung der folgenden Abfrage überprüft werden:
select table_name from all_tables where temporary = 'Y';
Entwicklertipps für globale temporäre Tabellen (GTT)
Nach dem Beispiel im PostgreSQL-Abschnitt:Um einen Bonus für die Kunden zu vergeben, die seit mehr als einem Jahr keine Einkäufe getätigt oder sich nicht angemeldet haben, hat die Verwendung globaler temporärer Tabellen in Oracle das gleiche Ziel wie in PostgreSQL:eine bessere Leistung zu erzielen entweder in der Ressourcenverbrauch oder Ausführungsgeschwindigkeit.
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>
Standardmäßig startet in Oracle ein SQL/PLSQL-Block/Anweisung implizit eine Transaktion.
DBA-Tipps für globale temporäre Tabellen (GTT)
Wie die Anweisung drop existiert nicht für globale temporäre Tabellen. Der Befehl zum Erstellen der Tabelle ist derselbe wie der vorherige:
CREATE GLOBAL TEMPORARY TABLE tt_customer
(
customer_id NUMBER
)
ON COMMIT DELETE ROWS;
Das entsprechende Code-Snippet in Oracle zum Löschen des Kunden Tabelle ist es die folgende:
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.
Die pg_global_temp_tables-Bibliothek
Wie oben erwähnt, können die temporären Tabellen in PostgreSQL nicht mit der Notation schema.table aufgerufen werden , also ist die Bibliothek pg_global_temp_tables (es gibt einige ähnliche Bibliotheken auf GitHub) eine sehr nützliche Problemumgehung, die bei Datenbankmigrationen von Oracle zu PostgreSQL verwendet werden kann.
Um die Oracle-Notation schema.temporary_table beizubehalten in Abfragen oder gespeicherten Prozeduren:
SELECT c.id,c.nam
FROM web_app.tt_customers tc,
Web_app.customers c
WHERE c.id = tc.id
Es erlaubt, die temporären Tabellen über den Code mit der Schemanotation zu belassen.
Im Grunde besteht es aus einer Ansicht:web_app.tt_customers unter dem Schema erstellt, auf dem es die temporäre Tabelle haben soll, und diese Ansicht fragt die temporäre Tabelle tt_customers ab über eine Funktion namens web_app.select_tt_customers :
CREATE OR REPLACE VIEW WEB_APP.TT_CUSTOMERS AS
SELECT * FROM WEB_APP.SELECT_TT_CUSTOMERS();
Diese Funktion gibt den Inhalt der temporären Tabelle zurück:
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;
Zusammenfassung
Die temporären Tabellen werden im Wesentlichen verwendet, um Zwischenergebnisse zu speichern und somit komplexe und schwere Berechnungen zu vermeiden,
Danach werden einige Eigenschaften von temporären Tabellen entweder in PostgreSQL oder Oracle aufgelistet:
- Es kann zur Ansicht verwendet werden
- Es kann den TRUNCATE-Befehl verwenden
- Es kann nicht partitioniert werden
- Die Fremdschlüsseleinschränkung für temporäre Tabellen ist nicht zulässig
- Diese Art von Tabellen ist eine Alternative für CTEs (Common Table Expressions), die den Oracle-Profis auch als WITH-Klausel bekannt ist
- In Bezug auf Sicherheit und Datenschutz sind diese Tabellen ein wertvolles Gut, da die Daten nur für eine aktuelle Sitzung sichtbar sind
- Die temporären Tabellen werden automatisch gelöscht (in PostgreSQL) oder gelöscht (in Oracle), sobald die Sitzung/Transaktion endet.
Für die temporären Tabellen in PostgreSQL ist es ratsam, nicht den gleichen Namen einer permanenten Tabelle in einer temporären Tabelle zu verwenden. Auf Oracle-Seite ist es eine gute Praxis, Statistiken für die Sitzungen zu erstellen, die ein beträchtliches Datenvolumen in GTT enthalten, um den kostenbasierten Optimierer (CBO) zu zwingen, den besten Plan für die Abfragen auszuwählen, die diese Art von Tabellen verwenden .