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

テーブルAPIとトランザクションAPIの違いを理解する

    TableAPIから始めましょう。これは、PL /SQLAPIを介して表へのアクセスを仲介する方法です。したがって、テーブルごとにパッケージがあり、データディクショナリから生成する必要があります。このパッケージは、テーブルに対してDMLを発行するための標準的な一連の手順と、データを取得するためのいくつかの関数を提供します。

    比較すると、TransactionalAPIは作業単位を表します。基盤となるデータベースオブジェクトに関する情報はまったく公開されません。トランザクションAPIは、より優れたカプセル化とよりクリーンなインターフェースを提供します。

    コントラストはこんな感じ。新しい部門を作成するための次のビジネスルールを検討してください。

    1. 新しい部門には名前と場所が必要です
    2. 新しい部門には、既存の従業員である必要があるマネージャーが必要です。
    3. 他の既存の従業員は新しい部門に異動する場合があります
    4. 新しい従業員が新しい部門に割り当てられる場合があります
    5. 新しい部門には、少なくとも2人の従業員(マネージャーを含む)が割り当てられている必要があります

    テーブルAPIを使用すると、トランザクションは次のようになります。

    DECLARE
        dno pls_integer;
        emp_count pls_integer;
    BEGIN
        dept_utils.insert_one_rec(:new_name, :new_loc, dno);
        emp_utils.update_one_rec(:new_mgr_no ,p_job=>'MGR’ ,p_deptno=>dno);
        emp_utils.update_multi_recs(:transfer_emp_array, p_deptno=>dno);
        FOR idx IN :new_hires_array.FIRST..:new_hires_array.LAST LOOP
            :new_hires_array(idx).deptno := dno;
        END LOOP;
        emp_utils.insert_multi_recs(:new_hires_array);
        emp_count := emp_utils.get_count(p_deptno=>dno); 
        IF emp_count < 2 THEN
            raise_application_error(-20000, ‘Not enough employees’);
        END IF;
    END;
    /
    

    一方、Transactional APIを使用すると、はるかに簡単になります。

    DECLARE
        dno subtype_pkg.deptno;
    BEGIN
        dept_txns.create_new_dept(:new_name
                                    , :new_loc
                                    , :new_mgr_no
                                    , :transfer_emps_array
                                    , :new_hires_array
                                    , dno);
    END;
    /
    

    では、なぜデータの取得に違いがあるのでしょうか。 Transactional APIアプローチは、一般的なget()を推奨しないためです。 非効率的なSELECTステートメントの不注意な使用を回避するために機能します。

    たとえば、従業員の給与とコミッションだけが必要な場合は、これをクエリします...

    select sal, comm
    into l_sal, l_comm
    from emp
    where empno = p_eno;
    

    ...これを実行するよりも優れています...

    l_emprec := emp_utils.get_whole_row(p_eno);
    

    ...特にEmployeeレコードにLOB列がある場合。

    また、以下よりも効率的です:

    l_sal := emp_utils.get_sal(p_eno);
    l_comm := emp_utils.get_comm(p_eno);
    

    ...これらのゲッターのそれぞれが個別のSELECTステートメントを実行する場合。これは不明ではありません。これは、データベースのパフォーマンスを低下させる悪いOOプラクティスです。

    Table APIの支持者は、開発者がSQLについて考える必要がないように保護しているという理由で彼らを主張しています。それらを非難する人々は、まったく同じ理由でテーブルAPIを嫌います。 。最高のテーブルAPIでさえ、RBAR処理を促進する傾向があります。毎回独自のSQLを作成すると、セットベースのアプローチを選択する可能性が高くなります。

    トランザクションAPIを使用しても、必ずしもget_resultset()の使用が除外されるわけではありません。 関数。クエリAPIにはまだ多くの価値があります。ただし、個々のテーブルのSELECTよりも、結合を実装するビューと関数から構築される可能性が高くなります。

    ちなみに、テーブルAPIの上にトランザクションAPIを構築することはお勧めできません。慎重に記述された結合ではなく、SQLステートメントをサイロ化しています。

    例として、リージョン内のすべての従業員の給与を更新するためのトランザクションAPIの2つの異なる実装を示します(リージョンは組織の大規模なセクションであり、部門はリージョンに割り当てられています)。

    最初のバージョンには、Table API呼び出しだけの純粋なSQLはありません。これは、ストローマンではないと思います。TableAPIパッケージで見たような機能を使用します(ただし、SET_XXX()プロシージャという名前ではなく動的SQLを使用するものもあります)。 。

    create or replace procedure adjust_sal_by_region
        (p_region in dept.region%type
               , p_sal_adjustment in number )
    as
        emps_rc sys_refcursor;
        emp_rec emp%rowtype;
        depts_rc sys_refcursor;
        dept_rec dept%rowtype;
    begin
        depts_rc := dept_utils.get_depts_by_region(p_region);
    
        << depts >>
        loop
            fetch depts_rc into dept_rec;
            exit when depts_rc%notfound;
            emps_rc := emp_utils.get_emps_by_dept(dept_rec.deptno);
    
            << emps >>
            loop
                fetch emps_rc into emp_rec;
                exit when emps_rc%notfound;
                emp_rec.sal := emp_rec.sal * p_sal_adjustment;
                emp_utils.set_sal(emp_rec.empno, emp_rec.sal);
            end loop emps;
    
        end loop depts;
    
    end adjust_sal_by_region;
    /
    

    SQLでの同等の実装:

    create or replace procedure adjust_sal_by_region
        (p_region in dept.region%type
               , p_sal_adjustment in number )
    as
    begin
        update emp e
        set e.sal = e.sal * p_sal_adjustment
        where e.deptno in ( select d.deptno 
                            from dept d
                            where d.region = p_region );
    end adjust_sal_by_region;
    /
    

    これは、以前のバージョンのネストされたカーソルループと単一行の更新よりもはるかに優れています。これは、SQLでは、リージョンごとに従業員を選択するために必要な結合を記述するのが簡単だからです。リージョンは従業員のキーではないため、テーブルAPIを使用するのは非常に困難です。

    公平を期すために、動的SQLをサポートするTable APIがある場合、状況は改善されますが、それでも理想的ではありません。

    create or replace procedure adjust_sal_by_region
        (p_region in dept.region%type
               , p_sal_adjustment in number )
    as
        emps_rc sys_refcursor;
        emp_rec emp%rowtype;
    begin
        emps_rc := emp_utils.get_all_emps(
                        p_where_clause=>'deptno in ( select d.deptno 
                            from dept d where d.region = '||p_region||' )' );
    
        << emps >>
        loop
            fetch emps_rc into emp_rec;
            exit when emps_rc%notfound;
            emp_rec.sal := emp_rec.sal * p_sal_adjustment;
            emp_utils.set_sal(emp_rec.empno, emp_rec.sal);
        end loop emps;
    
    end adjust_sal_by_region;
    /
    

    最後の言葉

    そうは言っても、テーブルAPIが役立つシナリオや、かなり標準的な方法で単一のテーブルとのみやり取りしたい場合があります。明らかなケースは、他のシステムからのデータフィードを生成または消費することです。 ETL。

    Table APIの使用を調査する場合は、StevenFeuersteinのQuestCodeGenユーティリティ(以前のQNXO)から始めるのが最適です。これはTAPIジェネレーターとほぼ同じくらい優れており、無料です。



    1. PostgreSQLデータベースのデプロイメントを自動化する方法

    2. OracleSql開発者でExplainPlanを表示するにはどうすればよいですか?

    3. データファイルを使用したデータベースへのRACのインストール

    4. PostgreSQL 9.3:動的ピボットテーブル