PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comparaison des tables temporaires pour PostgreSQL et Oracle GTT

Les tables temporaires sont un concept utile présent dans la plupart des SGBD, même si elles fonctionnent souvent différemment.

Ce blog décrit les fonctionnalités techniques de ce type de tables dans les bases de données PostgreSQL (version 11) ou Oracle (version 12c) avec quelques exemples spécifiques. Bien que l'objectif de ces tableaux puisse être le même pour tous les SGBD, leurs spécificités, ou le mode de mise en œuvre et de manipulation, sont complètement différents.

Cette fonctionnalité peut être utilisée à la fois par les développeurs ou les administrateurs de base de données pour stocker les résultats intermédiaires qui seront nécessaires pour un traitement ultérieur afin de fournir de bonnes métriques de performance.

Tables temporaires dans PostgreSQL

Dans PostgreSQL, ces objets ne sont valides que pour la session en cours :ils sont créés, utilisés et déposés au cours de la même session :la structure de la table et les données gérées ne sont visibles que pour la session en cours, ainsi les autres sessions n'ont pas accès à les tables temporaires créées sur les autres sessions.

Ci-dessous, un exemple simple pour créer une table temporaire est montré :

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

Les tables temporaires sont créées dans un schéma temporaire :pg_temp_nn et il est possible de créer des index sur ces tables :

creation index  tt_cusomer_idx_1 on tt_customer(customer_id)

Comme les lignes de données sur ces tables pourraient également être supprimées, il est possible de libérer le stockage occupé par l'exécution de vaccum commande :

VACUUM VERBOSE tt_customer

L'analyse La commande peut également être exécutée sur les tables temporaires afin de collecter les statistiques :

ANALYZE VERBOSE tt_customer;

Les deux commandes peuvent être exécutées pour ce type de table en tant que commande SQL, cependant, le autovaccum le démon qui les exécute n'agit pas sur les tables temporaires.

Un autre point important à considérer est lié aux tables permanentes et temporaires portant le même nom :une fois que cela se produit, seule la table permanente est prise en compte lorsqu'elle est appelée avec son schéma comme préfixe.

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)

Dans l'exemple précédent, alors que la table temporaire existe, toutes les références aux clients fait référence à ce tableau au lieu du tableau permanent.

Conseils de développeur pour les tableaux temporaires

Le but de cet exemple est d'attribuer un bonus aux clients qui n'ont pas effectué d'achats ou de connexion depuis plus d'un an, donc le script du développeur utilise plutôt des sous-requêtes dans les requêtes comme solution possible (ou l'utilisation de CTE instruction) peut utiliser des tables temporaires (ce qui est généralement plus rapide que d'utiliser des sous-requêtes) :

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)

Conseils DBA pour les tables temporaires

Une tâche typique des administrateurs de base de données consiste à purger toutes les tables volumineuses contenant des données qui ne sont plus nécessaires. Cela doit être fait très rapidement et cela arrive souvent. L'approche standard consiste à déplacer ces données vers une table historique dans un autre schéma ou vers une base de données à laquelle on accède moins souvent.

Ainsi, pour effectuer ce déplacement, en raison de problèmes de performances, la meilleure solution pourrait être d'utiliser des tables temporaires :

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

Dans cet exemple, la table temporaire a été créée avec l'option DROP, cela signifie donc qu'elle sera supprimée à la fin du bloc de transaction en cours.

Voici quelques autres informations importantes sur les tables temporaires PostgreSQL :

  • Les tables temporaires sont automatiquement supprimées à la fin d'une session ou, comme présenté dans l'exemple précédent, à la fin de la transaction en cours
  • Les tables permanentes portant le même nom ne sont pas visibles pour la session en cours tant que la table temporaire existe, sauf si elles sont référencées avec des noms qualifiés par le schéma
  • Tous les index créés sur une table temporaire sont également automatiquement temporaires
  • ON COMMIT conserve les lignes, c'est le comportement par défaut
  • Facultativement, GLOBAL ou LOCAL peut être écrit avant TEMPORARY ou TEMP. Cela ne fait actuellement aucune différence dans PostgreSQL et il est obsolète
  • L'aspirateur automatique Le démon ne peut pas accéder à ces tables et ne peut donc pas aspirer ou analyser les tables temporaires, cependant, comme indiqué précédemment, les commandes autovacuum et analyze peuvent être utilisées comme commandes SQL.

Tables temporaires globales (GTT) dans Oracle

Ce type de tables est connu dans le monde Oracle sous le nom de table temporaire globale (ou GTT). Ces objets sont persistants dans la base de données et peuvent être résumés par les caractéristiques suivantes :

  • La structure est statique et visible pour tous les utilisateurs, cependant, son contenu n'est visible que pour la session en cours
  • Il peut être créé dans un schéma spécifique (par défaut, il appartiendra à l'utilisateur qui émet la commande) et ils sont construits dans l'espace de table TEMP
  • Une fois créée dans la base de données, elle ne peut pas être recréée à chaque session, cependant, les données gérées par une session ne sont pas visibles pour les autres sessions
  • Il est possible de créer des index et de générer des statistiques
  • Comme la structure de ces tables est également définie dans la base de données, il n'est pas possible d'attribuer son nom à une table permanente (dans Oracle, deux objets ne peuvent pas avoir le même nom, même de types différents)
  • Ne générez pas trop de journaux redo et la surcharge d'annulation est également moindre par rapport à une table permanente (uniquement pour ces raisons, l'utilisation de GTT est plus rapide) pour toutes les versions antérieures à 12c. À partir de la version 12c, il existe un concept d'annulation temporaire, permettant d'écrire l'annulation d'un GTT dans l'espace de table temporaire, réduisant ainsi les annulations et les rétablissements.

En suivant le même exemple présenté dans PostgreSQL, la création d'un GTT est assez similaire :

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

Il est également possible de créer des index.

creation index  tt_cusomer_idx_1 on tt_customer(customer_id)

Avant Oracle 12c, la génération de statistiques pour une table temporaire globale avait un comportement de manière globale :les statistiques générées dans une session spécifique pour un GTT spécifique étaient visibles et utilisées pour les autres sessions (uniquement les statistiques, pas les données !), cependant, à partir de la version 12c, il est possible pour chaque session de générer ses propres statistiques.

Tout d'abord, il est nécessaire de définir la préférence global_temp_table_stats à la session :

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

puis la génération des statistiques :

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

La table temporaire globale existante pourrait être vérifiée par l'exécution de la requête suivante :

select table_name from all_tables where temporary = 'Y';

Conseils pour les développeurs concernant les tables temporaires globales (GTT)

En suivant l'exemple sur la section PostgreSQL :pour attribuer un bonus aux clients qui n'ont pas effectué d'achats ou de connexion depuis plus d'un an, l'utilisation de tables temporaires globales dans Oracle a le même objectif que dans PostgreSQL :obtenir de meilleures performances soit dans le l'utilisation des ressources ou la vitesse d'exécution.

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>

Par défaut dans Oracle, un bloc/instruction SQL/PLSQL démarre implicitement une transaction.

Conseils DBA pour les tables temporaires globales (GTT)

Comme l'instruction drop n'existe pas pour les tables temporaires globales la commande pour créer la table est la même que la précédente :

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

L'extrait de code équivalent dans Oracle pour purger le client tableau c'est le suivant :

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.

La bibliothèque pg_global_temp_tables

Comme mentionné ci-dessus, les tables temporaires dans PostgreSQL ne peuvent pas être appelées en utilisant la notation schema.table , donc la bibliothèque pg_global_temp_tables (il existe des bibliothèques similaires disponibles sur github) c'est une solution de contournement très utile à utiliser dans les migrations de bases de données d'Oracle vers PostgreSQL.

Afin de conserver la notation Oracle schema.temporary_table dans les requêtes ou les procédures stockées :

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

Il permet de rester les tables temporaires sur le code avec la notation schéma.

Fondamentalement, il s'agit d'une vue :web_app.tt_customers créé sous le schéma sur lequel il est censé avoir la table temporaire et cette vue interrogera la table temporaire tt_customers via une fonction appelée web_app.select_tt_customers :

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

Cette fonction renvoie le contenu de la table temporaire :

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;  

Résumé

Les tables temporaires servent essentiellement à stocker des résultats intermédiaires et ainsi éviter un calcul complexe et lourd,

Par la suite, il est répertorié certaines caractéristiques des tables temporaires dans PostgreSQL ou Oracle :

  • Il peut être utilisé à vue
  • Il peut utiliser la commande TRUNCATE
  • Il ne peut pas être partitionné
  • La contrainte de clé étrangère sur les tables temporaires n'est pas autorisée
  • Ce type de tables est une alternative aux CTE (Common Table Expressions) également connues des professionnels d'Oracle sous le nom de clause WITH
  • En termes de sécurité et de confidentialité, ces tableaux sont un atout précieux car les données ne sont visibles que pour une session en cours
  • Les tables temporaires sont automatiquement supprimées (dans PostgreSQL) ou supprimées (dans Oracle) une fois la session/transaction terminée.

Pour les tables temporaires dans PostgreSQL, il est conseillé de ne pas utiliser le même nom d'une table permanente dans une table temporaire. Du côté d'Oracle, il est recommandé de générer des statistiques pour les sessions qui incluent un volume considérable de données dans GTT afin de forcer le Cost-Based Optimizer (CBO) à choisir le meilleur plan pour les requêtes utilisant ce type de tables. .