sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLとOracleGTTの一時テーブルの比較

    一時テーブルは、多くの場合異なる動作をしますが、ほとんどのSGBDに存在する便利な概念です。

    このブログでは、PostgreSQL(バージョン11)またはOracle(バージョン12c)データベースのこの種のテーブルの技術的機能について、いくつかの具体的な例を挙げて説明しています。これらのテーブルの目的はすべてのSGBDで同じである可能性がありますが、それらの詳細、または実装と操作の方法は完全に異なります。

    この機能は、開発者またはデータベース管理者の両方が使用して、優れたパフォーマンスメトリックを提供するためにさらに処理するために必要となる中間結果を保存できます。

    PostgreSQLの一時テーブル

    PostgreSQLでは、これらのオブジェクトは現在のセッションでのみ有効です。同じセッションに沿って作成、使用、削除されます。テーブルの構造と管理対象データは現在のセッションでのみ表示されるため、他のセッションはにアクセスできません。他のセッションで作成された一時テーブル。

    以下に、一時テーブルを作成する簡単な例を示します。

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

    一時テーブルは、一時スキーマ pg_temp_nnで作成されます。 これらのテーブルにインデックスを作成することができます:

    creation index  tt_cusomer_idx_1 on tt_customer(customer_id)

    これらのテーブルのデータ行も削除される可能性があるため、 vaccum を実行することで、占有されているストレージを解放することができます。 コマンド:

    VACUUM VERBOSE tt_customer

    分析 統計を収集するために、一時テーブルに対してコマンドを実行することもできます。

    ANALYZE VERBOSE tt_customer;

    この種のテーブルでは、どちらのコマンドもSQLコマンドとして実行できますが、 autovaccum それらを実行するデーモンは、一時テーブルには作用しません。

    同じ名前の永続テーブルと一時テーブルに関連していることを考慮するもう1つの重要なポイント:一度発生すると、永続テーブルは、そのスキーマをプレフィックスとして呼び出されたときにのみ考慮されます。

    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)

    前の例から、一時テーブルが存在する間、すべての顧客への参照 永続的なテーブルではなく、このテーブルを参照します。

    一時テーブルの開発者向けのヒント

    この例の目的は、購入またはログインを1年以上行っていない顧客にボーナスを割り当てることです。そのため、開発者のスクリプトでは、代わりに、可能な解決策としてクエリでサブクエリを使用します(またはCTEを使用します)。ステートメント)は一時テーブルを使用できます(通常、サブクエリを使用するよりも高速です):

    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のヒント

    データベース管理者の一般的なタスクは、不要になったデータを含む巨大なテーブルを削除することです。これは非常に迅速に完了する必要があり、頻繁に発生します。標準的なアプローチは、このデータを別のスキーマの履歴テーブルまたはアクセス頻度の低いデータベースに移動することです。

    したがって、この移動を実行するには、パフォーマンスの問題があるため、一時テーブルを使用するのが最善の解決策になる可能性があります。

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

    この例では、一時テーブルはDROPオプションを使用して作成されているため、現在のトランザクションブロックの最後で削除されることを意味します。

    PostgreSQL一時テーブルに関するその他の重要な情報は次のとおりです。

    • 一時テーブルは、セッションの終了時、または前の例で示したように、現在のトランザクションの終了時に自動的に削除されます
    • 同じ名前の永続テーブルは、スキーマ修飾名で参照されていない限り、一時テーブルが存在する間は現在のセッションに表示されません。
    • 一時テーブルに作成されたインデックスも自動的に一時的になります
    • ONCOMMITは行を保持します。これがデフォルトの動作です
    • オプションで、GLOBALまたはLOCALをTEMPORARYまたはTEMPの前に書き込むことができます。これは現在PostgreSQLに違いはなく、非推奨です
    • autovacuum デーモンはこれらのテーブルにアクセスできないため、一時テーブルをバキュームまたは分析できません。ただし、前に示したように、autovacuumおよびanalyzeコマンドはSQLコマンドとして使用できます。

    Oracleのグローバル一時テーブル(GTT)

    この種のテーブルは、Oracleの世界ではGlobal Temporary Table(またはGTT)として知られています。これらのオブジェクトはデータベースに永続的であり、次の特性によって要約できます。

    • 構造は静的であり、すべてのユーザーに表示されますが、そのコンテンツは現在のセッションでのみ表示されます
    • 特定のスキーマで作成でき(デフォルトでは、コマンドを発行したユーザーが所有します)、TEMPテーブルスペースに構築されます
    • データベースで作成されると、各セッションで再度作成することはできませんが、セッションによって管理されるデータは、他のセッションでは表示されません。
    • インデックスの作成と統計の生成が可能です
    • これらのテーブルの構造もデータベースで定義されているため、その名前を永続テーブルに割り当てることはできません(Oracleでは、2つのオブジェクトが異なるタイプからでも同じ名前を持つことはできません)
    • 12cより前のバージョンでは、あまり多くのREDOログを生成しないでください。また、元に戻るオーバーヘッドは、永続的なテーブルと比較して少なくなります(これらの理由で、GTTを使用する方が高速です)。 12cバージョンからは、一時的な取り消しの概念があり、GTTの取り消しを一時的な表領域に書き込むことができるため、取り消しとやり直しが減ります。

    PostgreSQLで提示された同じ例に従うと、GTTの作成は非常に似ています:

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

    インデックスの作成も可能です。

    creation index  tt_cusomer_idx_1 on tt_customer(customer_id)

    Oracle 12c以前は、グローバル一時テーブルの統計の生成はグローバルな方法で動作していました。特定のGTTの特定のセッションで生成された統計は表示され、他のセッションで使用されていました(ただし、データではなく統計のみです)。バージョン12cから、各セッションで独自の統計を生成することが可能です。

    まず、設定を設定する必要があります global_temp_table_stats セッションへ :

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

    次に、統計の生成:

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

    既存のグローバル一時テーブルは、次のクエリを実行することで確認できます。

    select table_name from all_tables where temporary = 'Y';

    グローバル一時テーブル(GTT)の開発者向けのヒント

    PostgreSQLセクションの例に従って:購入またはログインを1年以上行っていない顧客にボーナスを割り当てるために、Oracleでのグローバル一時テーブルの使用にはPostgreSQLと同じ目標があります。リソースの使用または実行速度。

    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>

    Oracleのデフォルトでは、SQL/PLSQLブロック/ステートメントは暗黙的にトランザクションを開始します。

    グローバル一時テーブル(GTT)に関するDBAのヒント

    ステートメントとしてdrop グローバル一時テーブルには存在しません。テーブルを作成するコマンドは前のものと同じです:

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

    顧客を削除するためのOracleの同等のコードスニペット 表は次のとおりです:

    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ライブラリ

    上記のように、PostgreSQLの一時テーブルは schema.tableという表記を使用して呼び出すことはできません。 、したがって、pg_global_temp_tablesライブラリ(githubで利用可能な同様のライブラリがいくつかあります)は、OracleからPostgreSQLへのデータベース移行で使用するのに非常に便利な回避策です。

    Oracle表記を維持するためにschema.temporary_table クエリまたはストアドプロシージャの場合:

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

    スキーマ表記を使用して、コード上に一時テーブルを残すことができます。

    基本的に、これはビューで構成されます: web_app.tt_customers 一時テーブルがあるはずのスキーマの下に作成され、このビューは一時テーブルをクエリします tt_customers web_app.select_tt_customersという関数を使用します :

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

    この関数は一時テーブルの内容を返します:

    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;  

    概要

    一時テーブルは、基本的に中間結果を格納するために使用されるため、複雑で重いコンピューティングを回避します。

    その後、PostgreSQLまたはOracleのいずれかの一時テーブルのいくつかの特性をリストします。

    • ビューで使用できます
    • TRUNCATEコマンドを使用できます
    • パーティション化できません
    • 一時テーブルに対する外部キー制約は許可されていません
    • この種のテーブルは、Oracleの専門家にはWITH句としても知られているCTE(共通テーブル式)の代替手段です。
    • データは現在のセッションでのみ表示されるため、セキュリティとプライバシーの観点から、これらのテーブルは貴重な資産です。
    • セッション/トランザクションが終了すると、一時テーブルは自動的に削除されるか(PostgreSQLの場合)または削除されます(Oracleの場合)。

    PostgreSQLの一時テーブルの場合、一時テーブルで永続テーブルと同じ名前を使用しないことをお勧めします。 Oracle側では、Cost-Based Optimizer(CBO)にこれらの種類のテーブルを使用するクエリに最適なプランを選択させるために、GTTに大量のデータを含むセッションの統計を生成することをお勧めします。 。


    1. 日付範囲から日を生成する

    2. postgresで行番号を選択します

    3. 11gR2圧縮アドバイザー=悪

    4. BackupManagerを使用してデータベースを復元する方法