Deterministic functions

Hello
I'm trying to figure out if there are any rules by which it is possible to determine in a given situation, how many calls will be made to a deterministic function given the same inputs. I've put together a very basic test and for 100 rows with 10 different values, I get 70 calls to the deterministic function and 100 to the non-deterministic one:
SQL> CREATE OR REPLACE PACKAGE pkg_Test_Deterministic
  2  IS
  3
  4     FUNCTION f_Deterministic(a number)
  5     RETURN NUMBER
  6     DETERMINISTIC;
  7
  8     FUNCTION f_NonDeterministic(a number)
  9     RETURN NUMBER;
10
11     PROCEDURE p_PrintCounts;
12
13  END;
14  /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY pkg_Test_Deterministic
  2  IS
  3     pn_DeterministicCount           NUMBER;
  4     pn_NonDeterministicCount        NUMBER;
  5
  6
  7     FUNCTION f_Deterministic(a number)
  8     RETURN NUMBER
  9     DETERMINISTIC
10     IS
11
12     BEGIN
13
14             IF pn_DeterministicCount IS NULL THEN
15
16                     pn_DeterministicCount := 0;
17
18             END IF;
19
20             pn_DeterministicCount := pn_DeterministicCount + 1;
21
22             RETURN a;
23
24     END;
25
26
27     FUNCTION f_NonDeterministic(a number)
28     RETURN NUMBER
29     IS
30
31     BEGIN
32             IF pn_NonDeterministicCount IS NULL THEN
33
34                     pn_NonDeterministicCount := 0;
35
36             END IF;
37
38             pn_NonDeterministicCount := pn_NonDeterministicCount + 1;
39
40             RETURN a;
41
42     END;
43
44     PROCEDURE p_PrintCounts
45     IS
46
47     BEGIN
48
49             dbms_output.put_line('Deterministic Count '||TO_CHAR(pn_DeterministicCount));
50             dbms_output.put_line('Non Deterministic Count '||TO_CHAR(pn_NonDeterministicCount));
51
52             pn_DeterministicCount           := NULL;
53             pn_NonDeterministicCount        := NULL;
54     END;
55
56  END;
57  /
Package body created.
SQL>
SQL> CREATE TABLE dt_test_ids AS
  2  SELECT MOD(rownum,10) id FROM dual connect by level <= 100
  3  /
Table created.
SQL> set serveroutput on
SQL> select
  2     pkg_test_deterministic.f_Deterministic(id)
  3  from
  4     dt_test_ids;
PKG_TEST_DETERMINISTIC.F_DETERMINISTIC(ID)
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
                                         1
                                         2
                                         3
                                         4
                                         5
                                         6
                                         7
                                         8
                                         9
                                         0
100 rows selected.
SQL>
SQL> select
  2     pkg_test_deterministic.f_NonDeterministic(id)
  3  from
  4     dt_test_ids;
PKG_TEST_DETERMINISTIC.F_NONDETERMINISTIC(ID)
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
                                            1
                                            2
                                            3
                                            4
                                            5
                                            6
                                            7
                                            8
                                            9
                                            0
100 rows selected.
SQL>
SQL> exec pkg_test_deterministic.p_PrintCounts;
Deterministic Count 70
Non Deterministic Count 100
SQL> select * from v$version;
BANNER
Oracle Database 10g Enterprise Edition Release 10.2.0.2.0 - Prod
PL/SQL Release 10.2.0.2.0 - Production
CORE    10.2.0.2.0      Production
TNS for 32-bit Windows: Version 10.2.0.2.0 - Production
NLSRTL Version 10.2.0.2.0 - ProductionI scaled it up and found that it held true for 1000 rows (i.e. 700 calls to the deterministic function) and I tried it with a package that had no variables (in case that was somehow affecting it. Finally I tried a stand alone function and outputted using dbms_output, and found the same result again. The only thing that appeared to alter the result slightly (69 calls rather than 70) was to pass MOD(rownum,10) as the parameter rather than the column.
This is more out of pure curiosity than anything. Is there a particular event that can be traced to see when oracle is deciding to make a call/cache a set of values???
Cheers
David

Hello
Thank's for the link. I had read it but I missed the last line in Johnathan Lewis' post stating that there doesn't appear to be any fixed rule. I was hoping to find out a way of determining what those rules are. Oh well.
Thanks anyway
David

Similar Messages

  • Oracle 11g function based columns - deterministic function or not?

    Hi all, here is my situation:
    I added function based column in my table and created index on this column.
    I need this since in my ADF application, I need to be able to sort by this column.
    The function (that this column is based on) I had to make it DETERMINISTIC (otherwise it can not be done).
    So far so good.
    My function is accepting 3 parameters (all NUMBERs) which are practically 3 primary keys from 3 different tables. Based on which key is present, my function is returning "Code" - column (VARCHAR2) from any of those 3 tables. And for sure "Code" can change in any of those table.
    So my function is not really a DETERMINISTIC function.
    -Should I update the function and make it nondeterministic? Will it still work? Will the index be valid if the function is nondeterministic?
    -What is the consequence if it is not deterministic?
    -If I leave i as deterministic - somehow the result is cached. Will my function always going to be re-executed for each row (having on mind it is not really deterministic)?
    -Is there better solution than (function based column and index on it) in my case?
    Thanks, Vesna

    OK, Damorgan, here are some more details:
    Versin Numbers:
    Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
    PL/SQL Release 11.1.0.7.0 - Production
    TABLE:
    alter table MY_VIRTUAL_COLUMN add dispatch_customer_name  GENERATED ALWAYS AS (get_dispatch_customer_name(disloc_id, cus_id, cusloc_id)) VIRTUAL;
    create index dispatch_customer_name_i on MY_VIRTUAL_COLUMN(dispatch_customer_name);FUNCTION:
    CREATE OR REPLACE FUNCTION get_dispatch_customer_name(p_disloc_id NUMBER,
                                                          p_cus_id    NUMBER,
                                                          p_cusloc_id NUMBER)
       RETURN VARCHAR2 DETERMINISTIC IS
       v_result VARCHAR2(1000) := NULL;
    BEGIN
       IF p_cus_id IS NULL THEN
          IF p_cusloc_id IS NULL THEN
             SELECT d.name
               INTO v_result
               FROM dispatch_locations d
              WHERE d.disloc_id = p_disloc_id;
          ELSE
             SELECT l.name || ' (' || l.code || ')'
               INTO v_result
               FROM customer_locations l
              WHERE l.cusloc_id = p_cusloc_id;
          END IF;
       ELSE
          SELECT s.name || ' (' || s.code || ')'
            INTO v_result
            FROM customers s
           WHERE s.cus_id = p_cus_id;
       END IF;
       RETURN v_result;
    EXCEPTION
       WHEN OTHERS THEN
          RETURN NULL;
    END get_dispatch_customer_name;Hope this will help
    Thanks, Vesna

  • What are deterministic functions in oracle.??

    Hi,
    Can anyone give me any information regarding deterministic functions?
    Thanks

    I am not sure I understand what you are saying here. If you declare a function to be deterministic, then yes, Oracle may cache the results of the call and reuse the cached result when it sees another call to the function with the same parameters.
    However, given that value is different in your third rowm, it appears that you may have two different function calls here.
    Another thing to note is that you can declare any function to be deterministic, and Oracle will believe you. It does not make any attempt to decide whether you are correct or not.
    SQL> CREATE FUNCTION determ (p_num IN NUMBER) RETURN NUMBER
      2     DETERMINISTIC AS
      3  BEGIN
      4     RETURN p_num * DBMS_RANDOM.VALUE();
      5  END;
      6  /
    Function created.
    SQL> CREATE FUNCTION nondeterm (p_num IN NUMBER) RETURN NUMBER AS
      2  BEGIN
      3     RETURN p_num * DBMS_RANDOM.VALUE();
      4  END;
      5  /
    Function created.
    SQL> SELECT num, determ(num)
      2  FROM (SELECT rownum num FROM all_objects
      3        WHERE rownum <= 5
      4        UNION ALL
      5        SELECT rownum num FROM all_objects
      6        WHERE rownum <= 5);
           NUM DETERM(NUM)
             1  .808346096
             2  1.24224706
             3  2.55670491
             4  .814681413
             5  3.10128137
             1  .117673406
             2  1.24224706
             3  2.55670491
             4  .814681413
             5  3.10128137
    10 rows selected.
    SQL> SELECT num, nondeterm(num)
      2  FROM (SELECT rownum num FROM all_objects
      3        WHERE rownum <= 5
      4        UNION ALL
      5        SELECT rownum num FROM all_objects
      6        WHERE rownum <= 5);
           NUM NONDETERM(NUM)
             1     .536325578
             2      1.6236528
             3     .628491757
             4      2.6261965
             5     4.09006466
             1     .419011544
             2     1.01745468
             3     2.76301772
             4     2.32793484
             5     3.72438691So, the deterministic version did cache the function result (I'm not sure why it did not cache 1), but the non-deterministic version was called once for each row.
    John

  • Deterministic Functions don't work

    I have created the following package in Oracle 9i:
    CREATE OR REPLACE PACKAGE MyPackage IS
    FUNCTION MyDetFunc RETURN NUMBER DETERMINISTIC;
    END MyPackage;
    CREATE OR REPLACE PACKAGE BODY MyPackage IS
    i NUMBER := 0;
    FUNCTION MyDetFunc RETURN NUMBER IS
    BEGIN
    i := i + 1;
    RETURN i;
    END;
    END MyPackage;
    wich defines a function not really deterministic, but selon the documentation it shouldnt matter.
    Now I query a table with more than two rows.... And I get two different results!!!!!
    Same results can be achieved if you display a message with dbms_output, you can see the function is called every time someone calls it ... Exactly the same way as if it wasn't deterministic.
    I have done test with really deterministic functions
    and i have never got any performance improvement.
    Does anybody knows how this really works? Do you have any proof that deterministic functions work?
    What about functions in PL/SQL like sysdate that are "read consistent"? How is it implemented?

    On the contrary, deterministic functions do work, but only if you use them properly. I presume you are complaining about behaviour like this...
        SQL> SELECT MyPackage.MyDetFunc FROM t1;
         MYDETFUNC
                 1
                 2
                 3
                 4
                 5
                 6
                 7
                 8
                 9
        9 rows selected.
        SQL> SELECT MyPackage.MyDetFunc FROM t1 ORDER BY col3;
         MYDETFUNC
                10
                11
                12
                13
                14
                15
                17
                18
                16
        9 rows selected.
    SQL> The documentation states qute clearly that the database has no well of telling whether a function you assert is DETERMINISTIC actually is deterministic. You have asserted the function is DETERMINISTIC when clearly it is not. The bad results are therefore your fault.
    As for performance, well, DETERMINISTIC only affects function-based indexes. Check this out:
    CREATE OR REPLACE PACKAGE MyPackage
    IS
       FUNCTION MyDetFunc (n IN NUMBER) RETURN NUMBER DETERMINISTIC;
    END MyPackage;
    CREATE OR REPLACE PACKAGE BODY MyPackage
    IS
       FUNCTION MyDetFunc  (n IN NUMBER) RETURN NUMBER IS
          i NUMBER;
       BEGIN
          i := n + 0;
          RETURN i;
       END MyDetFunc;
    END MyPackage;
    SQL> SELECT * FROM t_10k WHERE MyPackage.MyDetFunc(col1) = 333;
          COL1
    COL2
    COL3
           333
    APC
    01-JUL-04
    Execution Plan
       0      SELECT STATEMENT Optimizer=CHOOSE
       1    0   TABLE ACCESS (FULL) OF 'T_10K'
    SQL> CREATE INDEX i_10k ON t_10k(MyPackage.MyPackage(col1));
    Index created.
    SQL> exec dbms_stats.gather_table_stats(user, 'T_10K')
    PL/SQL procedure successfully completed.
    SQL> exec dbms_stats.gather_index_stats(user, 'I_10K')
    PL/SQL procedure successfully completed.
    SQL> ALTER SESSION SET query_rewrite_enabled=true;
    Session altered.
    SQL> ALTER SESSION SET query_rewrite_integrity=trusted;
    Session altered.
    SQL> SELECT * FROM t_10k WHERE MyPackage.MyDetFunc(col1) = 333;
          COL1
    COL2
    COL3
           333
    APC
    01-JUL-04
    Execution Plan
       0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=16)
       1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T_10K' (Cost=2 Card=1 By
              tes=16)
       2    1     INDEX (RANGE SCAN) OF 'I_10K' (NON-UNIQUE) (Cost=1 Card=
              1)
    SQL> This time it used the index rather than doing a full table scan. That is a performance gain. Note that if I had used your original package definition the function would not have been deterministic and the result would have been wrong. This is not the database's fault: this is because your assertion was false.
    Cheers, APC

  • Simple question for deterministic functions

    It is written in oracle documents about deterministic functions:
    "Indicates that the function returns the same result value whenever it is called with the same values for its parameters."
    I am wondering is it cached? or is it performing in run time?
    for example when we execute a sql stement just one time and if we execute it again will the deterministic function performed?

    I am wondering is it cached? or is it performing in run time?
    PL/SQL Subprograms
    If result caching is enabled and the function was already called before with the same parameter value(s) (implying the result was cached) then the cached result gets returned (if still in the cache) without running the function code to compute the result.
    Regards
    Etbin

  • How to define a parallel, deterministic pl/sql function in OWB 11.2?

    Hi,
    at my customer site, we are starting with the new development work after upgrading from OWB 10.2 to 11.2 and we can't find the configuration parameter to define a parallel and deterministic function within a new package. The "old" function dialog in 10.2 had some checkboxes for those two features ...
    Thanks in advance
    Michael

    Thanks for the advice, the Cut & Copy idea from MccM is working fine, however is not really a solution for the problem. But we are using it as a workaround for the moment.
    Just for documentation: There already exists a bugfix, addressing the issue of lost parrallel and deterministic information during an upgrade from OWB10.2 to 11.2 (see bug 14673399 and patch 16082939)
    And for at least some of us with access to Oracle Support: Our onsite Oracle consultant opened a service request for this issue: 3-6773545351 (You will not be able to see the request unless You are an Oracle employee, but maybe the reference is helpful for You.)

  • Help optimizing query with function

    Hello experts,
    I need your help optmizing this query which has a condition that matches on results of non-deterministic function. The non-deterministic functino is fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY. Values that it returns depends on contents of a table, so I can't really create a function index.
    Any input will be appreciated. Thanks in advance!
    Sorry I couln't format the query plan properly. Can somebody advise how? Thanks again!
    Giovanni
    explain plan for
    WITH tg AS
    (SELECT taxgroup_code FROM taxgroup
    WHERE taxgroup_code = 'TAXGROUP2' --?
    AND taxgroup_delete_ind = 'N' AND taxgroup_active_ind = 'A'),
    le_hb AS
    (SELECT tgi.taxgroup_code, tgi.legalentity_id, tgi.hyperionbase_id, ou.orgunit_code, ou.hyperionbase_code
    FROM tg, taxgroupitem tgi, orgunit_vw ou
    WHERE tg.taxgroup_code = tgi.taxgroup_code
    AND tgi.legalentity_id = ou.legalentity_id AND tgi.hyperionbase_id = ou.hyperionbase_id
    UNION
    SELECT tgi.taxgroup_code, tgi.legalentity_id, ou.hyperionbase_id, ou.orgunit_code, ou.hyperionbase_code
    FROM tg, taxgroupitem tgi, orgunit_vw ou
    WHERE tg.taxgroup_code = tgi.taxgroup_code
    AND tgi.legalentity_id = ou.legalentity_id AND tgi.hyperionbase_id IS NULL),
    au AS
    (SELECT appusage_code FROM appusage WHERE appusage_code = 'CONSOLIDATION'),
    prs AS
    (SELECT prs_key,
    (CASE WHEN instr(prs_key, ':') = 0 THEN prs_key
    ELSE SUBSTR(prs_key, 1, (instr(prs_key, ':')-1) ) END) first_val
    FROM
    (SELECT fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(164415 --?
    ) prs_key
    FROM dual
    grs AS
    (SELECT prs.*, fd.fielddata_group_sequence fd_grpseq
    FROM prs, fielddata fd, le_hb
    WHERE prs.first_val = fd.fielddata_value
    AND le_hb.legalentity_id = fd.legalentity_id
    AND le_hb.hyperionbase_id = fd.hyperionbase_id),
    fdk AS
    (SELECT
    cd.celldef_id, fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(fd.fielddata_group_sequence) fd_key,
    fd.fielddata_value fd_val, fd.fielddata_group_sequence fd_grpseq,
    ROW_NUMBER() OVER (PARTITION BY cd.celldef_id, fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(fd.fielddata_group_sequence)
    ORDER BY fd.fielddata_group_sequence) rn,
    grs.prs_key
    FROM le_hb, grs, fielddata fd, tablecell tc, celldef cd, tabledef td, appusage au
    WHERE le_hb.legalentity_id = fd.legalentity_id AND le_hb.hyperionbase_id = fd.hyperionbase_id
    AND fd.fielddata_id = tc.fielddata_id AND tc.celldef_id = cd.celldef_id
    AND cd.tabledef_id = td.tabledef_id
    AND grs.fd_grpseq = fd.fielddata_parent_row_sequence
    and grs.prs_key = fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(fd.fielddata_parent_row_sequence)
    AND cd.celldef_key_ind = 'Y'
    AND fd.fielddata_delete_ind = 'N'
    AND td.tabledef_id = 2265
    fda AS
    (SELECT
    cd.celldef_id, fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(fd.fielddata_group_sequence) fd_key,
    TO_CHAR(TO_NUMBER(SUM(fd.fielddata_value))) fd_val,
    MIN(fd.fielddata_group_sequence) fd_grpseq,
    grs.prs_key
    FROM le_hb, grs, fielddata fd, tablecell tc, celldef cd, tabledef td
    WHERE le_hb.legalentity_id = fd.legalentity_id AND le_hb.hyperionbase_id = fd.hyperionbase_id
    AND fd.fielddata_id = tc.fielddata_id AND tc.celldef_id = cd.celldef_id
    AND cd.tabledef_id = td.tabledef_id
    AND grs.fd_grpseq = fd.fielddata_parent_row_sequence
    and grs.prs_key = fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(fd.fielddata_parent_row_sequence)
    AND cd.celldef_adjustable_ind = 'Y'
    AND fd.fielddata_delete_ind = 'N'
    AND td.tabledef_id = 2265
    GROUP BY cd.celldef_id, fedtaxpk.fedtaxpk_pkg.GETFIELDDATAGROUPSEQKEY(fd.fielddata_group_sequence),
    grs.prs_key
    SELECT NULL LEGALENTITY_ID, NULL hyperionbase_id, fdk.celldef_id, TO_CHAR(NULL) role_code, NULL userinfo_id, cd.celldef_adjustable_ind,
    'N' celldef_editable_ind, cd.celldef_filter_code, cd.celldef_validate_rule, cd.celldef_list_code,
    cd.celldef_longstring_ind, aua.appusageaccess_visible_ind celldef_viewable_ind,
    cd.celldef_column_sequence, cd.celldef_column_label,
    cd.celldef_column_sort_order, NULL tablecell_id, fdk.fd_grpseq tablecell_row_sequence, NULL tablecell_row_label,
    'N' tablecell_delete_ind, NULL tablecell_create_by, TO_DATE(NULL) tablecell_create_dt, TO_CHAR(NULL) tablecell_update_by,
    TO_DATE(NULL) tablecell_update_dt, NULL fielddata_id, TO_CHAR(NULL) datatype_code, NULL fielddata_adjref_id,
    fdk.fd_grpseq fielddata_group_sequence, NULL fielddata_parent_row_sequence, NULL lookup_id,
    fdk.fd_val fielddata_value, 'N' fielddata_delete_ind, TO_CHAR(NULL) fielddata_create_by,
    TO_DATE(NULL) fielddata_create_dt, TO_CHAR(NULL) fielddata_update_by, TO_DATE(NULL) fielddata_update_dt,
    fdk.fd_key
    FROM fdk, celldef cd, appusageaccess aua, au
    WHERE fdk.celldef_id = cd.celldef_id
    AND cd.celldef_id = aua.celldef_id
    AND aua.appusage_code = au.appusage_code
    AND fdk.rn = 1
    UNION ALL
    SELECT NULL LEGALENTITY_ID, NULL hyperionbase_id, fda.celldef_id, TO_CHAR(NULL) role_code, NULL userinfo_id, cd.celldef_adjustable_ind,
    'N' celldef_editable_ind, cd.celldef_filter_code, cd.celldef_validate_rule, cd.celldef_list_code,
    cd.celldef_longstring_ind, aua.appusageaccess_visible_ind celldef_viewable_ind,
    cd.celldef_column_sequence, cd.celldef_column_label,
    cd.celldef_column_sort_order, NULL tablecell_id, fda.fd_grpseq tablecell_row_sequence, NULL tablecell_row_label,
    'N' tablecell_delete_ind, NULL tablecell_create_by, TO_DATE(NULL) tablecell_create_dt, TO_CHAR(NULL) tablecell_update_by,
    TO_DATE(NULL) tablecell_update_dt, NULL fielddata_id, TO_CHAR(NULL) datatype_code, NULL fielddata_adjref_id,
    fda.fd_grpseq fielddata_group_sequence, NULL fielddata_parent_row_sequence, NULL lookup_id,
    fda.fd_val fielddata_value, 'N' fielddata_delete_ind, TO_CHAR(NULL) fielddata_create_by,
    TO_DATE(NULL) fielddata_create_dt, TO_CHAR(NULL) fielddata_update_by, TO_DATE(NULL) fielddata_update_dt,
    fda.fd_key
    FROM fda, celldef cd, appusageaccess aua, au
    WHERE fda.celldef_id = cd.celldef_id
    AND cd.celldef_id = aua.celldef_id
    AND aua.appusage_code = au.appusage_code
    ORDER BY fielddata_group_sequence, celldef_column_sequence
    Query Plan:
    Plan hash value: 522363234
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | 2 | 6227 | 249 (2)| 00:00:03 |
    | 1 | TEMP TABLE TRANSFORMATION | | | | | |
    | 2 | LOAD AS SELECT | | | | | |
    |* 3 | TABLE ACCESS BY INDEX ROWID | TAXGROUP | 1 | 14 | 1 (0)| 00:00:01 |
    |* 4 | INDEX UNIQUE SCAN | PK_TAXGROUP | 1 | | 0 (0)| 00:00:01 |
    | 5 | LOAD AS SELECT | | | | | |
    | 6 | SORT UNIQUE | | 4 | 224 | 12 (59)| 00:00:01 |
    | 7 | UNION-ALL | | | | | |
    | 8 | TABLE ACCESS BY INDEX ROWID | ORGUNIT | 1 | 29 | 2 (0)| 00:00:01 |
    | 9 | NESTED LOOPS | | 1 | 56 | 5 (0)| 00:00:01 |
    | 10 | NESTED LOOPS | | 1 | 27 | 3 (0)| 00:00:01 |
    | 11 | VIEW | | 1 | 10 | 2 (0)| 00:00:01 |
    | 12 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B51_2EBE182 | 1 | 10 | 2 (0)| 00:00:01 |
    |* 13 | TABLE ACCESS BY INDEX ROWID | TAXGROUPITEM | 1 | 17 | 1 (0)| 00:00:01 |
    |* 14 | INDEX RANGE SCAN | XF1_TAXGROUPITEM_TAXGROUP | 1 | | 0 (0)| 00:00:01 |
    |* 15 | INDEX RANGE SCAN | XF1_ORGUNIT_ID | 1 | | 1 (0)| 00:00:01 |
    | 16 | TABLE ACCESS BY INDEX ROWID | ORGUNIT | 3 | 87 | 2 (0)| 00:00:01 |
    | 17 | NESTED LOOPS | | 3 | 168 | 5 (0)| 00:00:01 |
    | 18 | NESTED LOOPS | | 1 | 27 | 3 (0)| 00:00:01 |
    | 19 | VIEW | | 1 | 10 | 2 (0)| 00:00:01 |
    | 20 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B51_2EBE182 | 1 | 10 | 2 (0)| 00:00:01 |
    |* 21 | TABLE ACCESS BY INDEX ROWID | TAXGROUPITEM | 1 | 17 | 1 (0)| 00:00:01 |
    |* 22 | INDEX RANGE SCAN | XF1_TAXGROUPITEM_TAXGROUP | 1 | | 0 (0)| 00:00:01 |
    |* 23 | INDEX RANGE SCAN | XF1_ORGUNIT_ID | 3 | | 1 (0)| 00:00:01 |
    | 24 | LOAD AS SELECT | | | | | |
    |* 25 | INDEX UNIQUE SCAN | PK_APPUSAGE | 1 | 10 | 0 (0)| 00:00:01 |
    | 26 | LOAD AS SELECT | | | | | |
    |* 27 | TABLE ACCESS BY INDEX ROWID | FIELDDATA | 7 | 147 | 28 (0)| 00:00:01 |
    | 28 | NESTED LOOPS | | 27 | 1269 | 117 (1)| 00:00:02 |
    | 29 | NESTED LOOPS | | 4 | 104 | 4 (0)| 00:00:01 |
    | 30 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
    | 31 | VIEW | | 4 | 104 | 2 (0)| 00:00:01 |
    | 32 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B52_2EBE182 | 4 | 388 | 2 (0)| 00:00:01 |
    |* 33 | INDEX RANGE SCAN | XF11_DATA_LE_HB | 117 | | 12 (0)| 00:00:01 |
    | 34 | SORT ORDER BY | | 2 | 6227 | 248 (51)| 00:00:03 |
    | 35 | UNION-ALL | | | | | |
    | 36 | NESTED LOOPS | | 1 | 4110 | 125 (2)| 00:00:02 |
    | 37 | MERGE JOIN CARTESIAN | | 1 | 4093 | 124 (2)| 00:00:02 |
    | 38 | NESTED LOOPS | | 1 | 4076 | 122 (2)| 00:00:02 |
    |* 39 | VIEW | | 1 | 4043 | 121 (2)| 00:00:02 |
    |* 40 | WINDOW SORT PUSHED RANK | | 1 | 2099 | 121 (2)| 00:00:02 |
    | 41 | MERGE JOIN CARTESIAN | | 1 | 2099 | 120 (1)| 00:00:02 |
    | 42 | NESTED LOOPS | | 1 | 2099 | 119 (1)| 00:00:02 |
    | 43 | NESTED LOOPS | | 1 | 2088 | 118 (1)| 00:00:02 |
    |* 44 | HASH JOIN | | 1 | 2077 | 117 (1)| 00:00:02 |
    |* 45 | TABLE ACCESS BY INDEX ROWID| FIELDDATA | 117 | 3744 | 28 (0)| 00:00:01 |
    | 46 | NESTED LOOPS | | 466 | 28892 | 114 (0)| 00:00:02 |
    | 47 | NESTED LOOPS | | 4 | 120 | 2 (0)| 00:00:01 |
    |* 48 | INDEX UNIQUE SCAN | PK_TABLEDEF | 1 | 4 | 0 (0)| 00:00:01 |
    | 49 | VIEW | | 4 | 104 | 2 (0)| 00:00:01 |
    | 50 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B52_2EBE182 | 4 | 388 | 2 (0)| 00:00:01 |
    |* 51 | INDEX RANGE SCAN | XF11_DATA_LE_HB | 117 | | 12 (0)| 00:00:01 |
    | 52 | VIEW | | 27 | 54405 | 2 (0)| 00:00:01 |
    | 53 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B54_2EBE182 | 27 | 1269 | 2 (0)| 00:00:01 |
    | 54 | TABLE ACCESS BY INDEX ROWID | TABLECELL | 1 | 11 | 1 (0)| 00:00:01 |
    |* 55 | INDEX UNIQUE SCAN | XF1_TBLCEL_DATA | 1 | | 0 (0)| 00:00:01 |
    |* 56 | TABLE ACCESS BY INDEX ROWID | CELLDEF | 1 | 11 | 1 (0)| 00:00:01 |
    |* 57 | INDEX UNIQUE SCAN | PK_CELLDEF | 1 | | 0 (0)| 00:00:01 |
    | 58 | BUFFER SORT | | 5 | | 120 (2)| 00:00:02 |
    | 59 | INDEX FULL SCAN | PK_APPUSAGE | 5 | | 1 (0)| 00:00:01 |
    | 60 | TABLE ACCESS BY INDEX ROWID | CELLDEF | 1 | 33 | 1 (0)| 00:00:01 |
    |* 61 | INDEX UNIQUE SCAN | PK_CELLDEF | 1 | | 0 (0)| 00:00:01 |
    | 62 | BUFFER SORT | | 1 | 17 | 123 (2)| 00:00:02 |
    | 63 | VIEW | | 1 | 17 | 2 (0)| 00:00:01 |
    | 64 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B53_2EBE182 | 1 | 10 | 2 (0)| 00:00:01 |
    | 65 | TABLE ACCESS BY INDEX ROWID | APPUSAGEACCESS | 1 | 17 | 1 (0)| 00:00:01 |
    |* 66 | INDEX UNIQUE SCAN | AK_APPUSAGEACCESS | 1 | | 0 (0)| 00:00:01 |
    | 67 | NESTED LOOPS | | 1 | 2117 | 124 (2)| 00:00:02 |
    | 68 | MERGE JOIN CARTESIAN | | 1 | 2100 | 123 (2)| 00:00:02 |
    | 69 | NESTED LOOPS | | 1 | 2083 | 121 (2)| 00:00:02 |
    | 70 | VIEW | | 1 | 2050 | 120 (2)| 00:00:02 |
    | 71 | HASH GROUP BY | | 1 | 2091 | 120 (2)| 00:00:02 |
    | 72 | NESTED LOOPS | | 1 | 2091 | 119 (1)| 00:00:02 |
    | 73 | NESTED LOOPS | | 1 | 2080 | 118 (1)| 00:00:02 |
    |* 74 | HASH JOIN | | 1 | 2069 | 117 (1)| 00:00:02 |
    |* 75 | TABLE ACCESS BY INDEX ROWID | FIELDDATA | 117 | 3744 | 28 (0)| 00:00:01 |
    | 76 | NESTED LOOPS | | 466 | 28892 | 114 (0)| 00:00:02 |
    | 77 | NESTED LOOPS | | 4 | 120 | 2 (0)| 00:00:01 |
    |* 78 | INDEX UNIQUE SCAN | PK_TABLEDEF | 1 | 4 | 0 (0)| 00:00:01 |
    | 79 | VIEW | | 4 | 104 | 2 (0)| 00:00:01 |
    | 80 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B52_2EBE182 | 4 | 388 | 2 (0)| 00:00:01 |
    |* 81 | INDEX RANGE SCAN | XF11_DATA_LE_HB | 117 | | 12 (0)| 00:00:01 |
    | 82 | VIEW | | 27 | 54189 | 2 (0)| 00:00:01 |
    | 83 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B54_2EBE182 | 27 | 1269 | 2 (0)| 00:00:01 |
    | 84 | TABLE ACCESS BY INDEX ROWID | TABLECELL | 1 | 11 | 1 (0)| 00:00:01 |
    |* 85 | INDEX UNIQUE SCAN | XF1_TBLCEL_DATA | 1 | | 0 (0)| 00:00:01 |
    |* 86 | TABLE ACCESS BY INDEX ROWID | CELLDEF | 1 | 11 | 1 (0)| 00:00:01 |
    |* 87 | INDEX UNIQUE SCAN | PK_CELLDEF | 1 | | 0 (0)| 00:00:01 |
    | 88 | TABLE ACCESS BY INDEX ROWID | CELLDEF | 1 | 33 | 1 (0)| 00:00:01 |
    |* 89 | INDEX UNIQUE SCAN | PK_CELLDEF | 1 | | 0 (0)| 00:00:01 |
    | 90 | BUFFER SORT | | 1 | 17 | 122 (2)| 00:00:02 |
    | 91 | VIEW | | 1 | 17 | 2 (0)| 00:00:01 |
    | 92 | TABLE ACCESS FULL | SYS_TEMP_0FD9D9B53_2EBE182 | 1 | 10 | 2 (0)| 00:00:01 |
    | 93 | TABLE ACCESS BY INDEX ROWID | APPUSAGEACCESS | 1 | 17 | 1 (0)| 00:00:01 |
    |* 94 | INDEX UNIQUE SCAN | AK_APPUSAGEACCESS | 1 | | 0 (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    3 - filter("TAXGROUP_DELETE_IND"='N' AND "TAXGROUP_ACTIVE_IND"='A')
    4 - access("TAXGROUP_CODE"='TAXGROUP2')
    13 - filter("TGI"."HYPERIONBASE_ID" IS NOT NULL)
    14 - access("TG"."TAXGROUP_CODE"="TGI"."TAXGROUP_CODE")
    15 - access("TGI"."LEGALENTITY_ID"="OU"."ORGUNIT_ID" AND "TGI"."HYPERIONBASE_ID"="OU"."HYPERIONBASE_ID")
    21 - filter("TGI"."HYPERIONBASE_ID" IS NULL)
    22 - access("TG"."TAXGROUP_CODE"="TGI"."TAXGROUP_CODE")
    23 - access("TGI"."LEGALENTITY_ID"="OU"."ORGUNIT_ID")
    25 - access("APPUSAGE_CODE"='CONSOLIDATION')
    27 - filter("FD"."FIELDDATA_VALUE"=CASE INSTR("FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(164415),':') WHEN 0
    THEN "FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(164415) ELSE
    SUBSTR("FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(164415),1,INSTR("FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(16441
    5),':')-1) END )
    33 - access("LE_HB"."LEGALENTITY_ID"="FD"."LEGALENTITY_ID" AND
    "LE_HB"."HYPERIONBASE_ID"="FD"."HYPERIONBASE_ID")
    39 - filter("FDK"."RN"=1)
    40 - filter(ROW_NUMBER() OVER ( PARTITION BY "CD"."CELLDEF_ID","FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"("FD"
    ."FIELDDATA_GROUP_SEQUENCE") ORDER BY "FD"."FIELDDATA_GROUP_SEQUENCE")<=1)
    44 - access("GRS"."FD_GRPSEQ"="FD"."FIELDDATA_PARENT_ROW_SEQUENCE" AND
    "GRS"."PRS_KEY"="FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"("FD"."FIELDDATA_PARENT_ROW_SEQUENCE"))
    45 - filter("FD"."FIELDDATA_DELETE_IND"='N')
    48 - access("TD"."TABLEDEF_ID"=2265)
    51 - access("LE_HB"."LEGALENTITY_ID"="FD"."LEGALENTITY_ID" AND
    "LE_HB"."HYPERIONBASE_ID"="FD"."HYPERIONBASE_ID")
    55 - access("FD"."FIELDDATA_ID"="TC"."FIELDDATA_ID")
    56 - filter("CD"."TABLEDEF_ID"=2265 AND "CD"."CELLDEF_KEY_IND"='Y')
    57 - access("TC"."CELLDEF_ID"="CD"."CELLDEF_ID")
    61 - access("FDK"."CELLDEF_ID"="CD"."CELLDEF_ID")
    66 - access("AUA"."APPUSAGE_CODE"="AU"."APPUSAGE_CODE" AND "CD"."CELLDEF_ID"="AUA"."CELLDEF_ID")
    74 - access("GRS"."FD_GRPSEQ"="FD"."FIELDDATA_PARENT_ROW_SEQUENCE" AND
    "GRS"."PRS_KEY"="FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"("FD"."FIELDDATA_PARENT_ROW_SEQUENCE"))
    75 - filter("FD"."FIELDDATA_DELETE_IND"='N')
    78 - access("TD"."TABLEDEF_ID"=2265)
    81 - access("LE_HB"."LEGALENTITY_ID"="FD"."LEGALENTITY_ID" AND
    "LE_HB"."HYPERIONBASE_ID"="FD"."HYPERIONBASE_ID")
    85 - access("FD"."FIELDDATA_ID"="TC"."FIELDDATA_ID")
    86 - filter("CD"."TABLEDEF_ID"=2265 AND "CD"."CELLDEF_ADJUSTABLE_IND"='Y')
    87 - access("TC"."CELLDEF_ID"="CD"."CELLDEF_ID")
    89 - access("FDA"."CELLDEF_ID"="CD"."CELLDEF_ID")
    94 - access("AUA"."APPUSAGE_CODE"="AU"."APPUSAGE_CODE" AND "CD"."CELLDEF_ID"="AUA"."CELLDEF_ID")

    Thanks cd.
    Here's the query plan:
    Query Plan:
    Plan hash value: 522363234
    | Id  | Operation                               | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT                        |                            |     2 |  6227 |   249   (2)| 00:00:03 |
    |   1 |  TEMP TABLE TRANSFORMATION              |                            |       |       |            |          |
    |   2 |   LOAD AS SELECT                        |                            |       |       |            |          |
    |*  3 |    TABLE ACCESS BY INDEX ROWID          | TAXGROUP                   |     1 |    14 |     1   (0)| 00:00:01 |
    |*  4 |     INDEX UNIQUE SCAN                   | PK_TAXGROUP                |     1 |       |     0   (0)| 00:00:01 |
    |   5 |   LOAD AS SELECT                        |                            |       |       |            |          |
    |   6 |    SORT UNIQUE                          |                            |     4 |   224 |    12  (59)| 00:00:01 |
    |   7 |     UNION-ALL                           |                            |       |       |            |          |
    |   8 |      TABLE ACCESS BY INDEX ROWID        | ORGUNIT                    |     1 |    29 |     2   (0)| 00:00:01 |
    |   9 |       NESTED LOOPS                      |                            |     1 |    56 |     5   (0)| 00:00:01 |
    |  10 |        NESTED LOOPS                     |                            |     1 |    27 |     3   (0)| 00:00:01 |
    |  11 |         VIEW                            |                            |     1 |    10 |     2   (0)| 00:00:01 |
    |  12 |          TABLE ACCESS FULL              | SYS_TEMP_0FD9D9B51_2EBE182 |     1 |    10 |     2   (0)| 00:00:01 |
    |* 13 |         TABLE ACCESS BY INDEX ROWID     | TAXGROUPITEM               |     1 |    17 |     1   (0)| 00:00:01 |
    |* 14 |          INDEX RANGE SCAN               | XF1_TAXGROUPITEM_TAXGROUP  |     1 |       |     0   (0)| 00:00:01 |
    |* 15 |        INDEX RANGE SCAN                 | XF1_ORGUNIT_ID             |     1 |       |     1   (0)| 00:00:01 |
    |  16 |      TABLE ACCESS BY INDEX ROWID        | ORGUNIT                    |     3 |    87 |     2   (0)| 00:00:01 |
    |  17 |       NESTED LOOPS                      |                            |     3 |   168 |     5   (0)| 00:00:01 |
    |  18 |        NESTED LOOPS                     |                            |     1 |    27 |     3   (0)| 00:00:01 |
    |  19 |         VIEW                            |                            |     1 |    10 |     2   (0)| 00:00:01 |
    |  20 |          TABLE ACCESS FULL              | SYS_TEMP_0FD9D9B51_2EBE182 |     1 |    10 |     2   (0)| 00:00:01 |
    |* 21 |         TABLE ACCESS BY INDEX ROWID     | TAXGROUPITEM               |     1 |    17 |     1   (0)| 00:00:01 |
    |* 22 |          INDEX RANGE SCAN               | XF1_TAXGROUPITEM_TAXGROUP  |     1 |       |     0   (0)| 00:00:01 |
    |* 23 |        INDEX RANGE SCAN                 | XF1_ORGUNIT_ID             |     3 |       |     1   (0)| 00:00:01 |
    |  24 |   LOAD AS SELECT                        |                            |       |       |            |          |
    |* 25 |    INDEX UNIQUE SCAN                    | PK_APPUSAGE                |     1 |    10 |     0   (0)| 00:00:01 |
    |  26 |   LOAD AS SELECT                        |                            |       |       |            |          |
    |* 27 |    TABLE ACCESS BY INDEX ROWID          | FIELDDATA                  |     7 |   147 |    28   (0)| 00:00:01 |
    |  28 |     NESTED LOOPS                        |                            |    27 |  1269 |   117   (1)| 00:00:02 |
    |  29 |      NESTED LOOPS                       |                            |     4 |   104 |     4   (0)| 00:00:01 |
    |  30 |       FAST DUAL                         |                            |     1 |       |     2   (0)| 00:00:01 |
    |  31 |       VIEW                              |                            |     4 |   104 |     2   (0)| 00:00:01 |
    |  32 |        TABLE ACCESS FULL                | SYS_TEMP_0FD9D9B52_2EBE182 |     4 |   388 |     2   (0)| 00:00:01 |
    |* 33 |      INDEX RANGE SCAN                   | XF11_DATA_LE_HB            |   117 |       |    12   (0)| 00:00:01 |
    |  34 |   SORT ORDER BY                         |                            |     2 |  6227 |   248  (51)| 00:00:03 |
    |  35 |    UNION-ALL                            |                            |       |       |            |          |
    |  36 |     NESTED LOOPS                        |                            |     1 |  4110 |   125   (2)| 00:00:02 |
    |  37 |      MERGE JOIN CARTESIAN               |                            |     1 |  4093 |   124   (2)| 00:00:02 |
    |  38 |       NESTED LOOPS                      |                            |     1 |  4076 |   122   (2)| 00:00:02 |
    |* 39 |        VIEW                             |                            |     1 |  4043 |   121   (2)| 00:00:02 |
    |* 40 |         WINDOW SORT PUSHED RANK         |                            |     1 |  2099 |   121   (2)| 00:00:02 |
    |  41 |          MERGE JOIN CARTESIAN           |                            |     1 |  2099 |   120   (1)| 00:00:02 |
    |  42 |           NESTED LOOPS                  |                            |     1 |  2099 |   119   (1)| 00:00:02 |
    |  43 |            NESTED LOOPS                 |                            |     1 |  2088 |   118   (1)| 00:00:02 |
    |* 44 |             HASH JOIN                   |                            |     1 |  2077 |   117   (1)| 00:00:02 |
    |* 45 |              TABLE ACCESS BY INDEX ROWID| FIELDDATA                  |   117 |  3744 |    28   (0)| 00:00:01 |
    |  46 |               NESTED LOOPS              |                            |   466 | 28892 |   114   (0)| 00:00:02 |
    |  47 |                NESTED LOOPS             |                            |     4 |   120 |     2   (0)| 00:00:01 |
    |* 48 |                 INDEX UNIQUE SCAN       | PK_TABLEDEF                |     1 |     4 |     0   (0)| 00:00:01 |
    |  49 |                 VIEW                    |                            |     4 |   104 |     2   (0)| 00:00:01 |
    |  50 |                  TABLE ACCESS FULL      | SYS_TEMP_0FD9D9B52_2EBE182 |     4 |   388 |     2   (0)| 00:00:01 |
    |* 51 |                INDEX RANGE SCAN         | XF11_DATA_LE_HB            |   117 |       |    12   (0)| 00:00:01 |
    |  52 |              VIEW                       |                            |    27 | 54405 |     2   (0)| 00:00:01 |
    |  53 |               TABLE ACCESS FULL         | SYS_TEMP_0FD9D9B54_2EBE182 |    27 |  1269 |     2   (0)| 00:00:01 |
    |  54 |             TABLE ACCESS BY INDEX ROWID | TABLECELL                  |     1 |    11 |     1   (0)| 00:00:01 |
    |* 55 |              INDEX UNIQUE SCAN          | XF1_TBLCEL_DATA            |     1 |       |     0   (0)| 00:00:01 |
    |* 56 |            TABLE ACCESS BY INDEX ROWID  | CELLDEF                    |     1 |    11 |     1   (0)| 00:00:01 |
    |* 57 |             INDEX UNIQUE SCAN           | PK_CELLDEF                 |     1 |       |     0   (0)| 00:00:01 |
    |  58 |           BUFFER SORT                   |                            |     5 |       |   120   (2)| 00:00:02 |
    |  59 |            INDEX FULL SCAN              | PK_APPUSAGE                |     5 |       |     1   (0)| 00:00:01 |
    |  60 |        TABLE ACCESS BY INDEX ROWID      | CELLDEF                    |     1 |    33 |     1   (0)| 00:00:01 |
    |* 61 |         INDEX UNIQUE SCAN               | PK_CELLDEF                 |     1 |       |     0   (0)| 00:00:01 |
    |  62 |       BUFFER SORT                       |                            |     1 |    17 |   123   (2)| 00:00:02 |
    |  63 |        VIEW                             |                            |     1 |    17 |     2   (0)| 00:00:01 |
    |  64 |         TABLE ACCESS FULL               | SYS_TEMP_0FD9D9B53_2EBE182 |     1 |    10 |     2   (0)| 00:00:01 |
    |  65 |      TABLE ACCESS BY INDEX ROWID        | APPUSAGEACCESS             |     1 |    17 |     1   (0)| 00:00:01 |
    |* 66 |       INDEX UNIQUE SCAN                 | AK_APPUSAGEACCESS          |     1 |       |     0   (0)| 00:00:01 |
    |  67 |     NESTED LOOPS                        |                            |     1 |  2117 |   124   (2)| 00:00:02 |
    |  68 |      MERGE JOIN CARTESIAN               |                            |     1 |  2100 |   123   (2)| 00:00:02 |
    |  69 |       NESTED LOOPS                      |                            |     1 |  2083 |   121   (2)| 00:00:02 |
    |  70 |        VIEW                             |                            |     1 |  2050 |   120   (2)| 00:00:02 |
    |  71 |         HASH GROUP BY                   |                            |     1 |  2091 |   120   (2)| 00:00:02 |
    |  72 |          NESTED LOOPS                   |                            |     1 |  2091 |   119   (1)| 00:00:02 |
    |  73 |           NESTED LOOPS                  |                            |     1 |  2080 |   118   (1)| 00:00:02 |
    |* 74 |            HASH JOIN                    |                            |     1 |  2069 |   117   (1)| 00:00:02 |
    |* 75 |             TABLE ACCESS BY INDEX ROWID | FIELDDATA                  |   117 |  3744 |    28   (0)| 00:00:01 |
    |  76 |              NESTED LOOPS               |                            |   466 | 28892 |   114   (0)| 00:00:02 |
    |  77 |               NESTED LOOPS              |                            |     4 |   120 |     2   (0)| 00:00:01 |
    |* 78 |                INDEX UNIQUE SCAN        | PK_TABLEDEF                |     1 |     4 |     0   (0)| 00:00:01 |
    |  79 |                VIEW                     |                            |     4 |   104 |     2   (0)| 00:00:01 |
    |  80 |                 TABLE ACCESS FULL       | SYS_TEMP_0FD9D9B52_2EBE182 |     4 |   388 |     2   (0)| 00:00:01 |
    |* 81 |               INDEX RANGE SCAN          | XF11_DATA_LE_HB            |   117 |       |    12   (0)| 00:00:01 |
    |  82 |             VIEW                        |                            |    27 | 54189 |     2   (0)| 00:00:01 |
    |  83 |              TABLE ACCESS FULL          | SYS_TEMP_0FD9D9B54_2EBE182 |    27 |  1269 |     2   (0)| 00:00:01 |
    |  84 |            TABLE ACCESS BY INDEX ROWID  | TABLECELL                  |     1 |    11 |     1   (0)| 00:00:01 |
    |* 85 |             INDEX UNIQUE SCAN           | XF1_TBLCEL_DATA            |     1 |       |     0   (0)| 00:00:01 |
    |* 86 |           TABLE ACCESS BY INDEX ROWID   | CELLDEF                    |     1 |    11 |     1   (0)| 00:00:01 |
    |* 87 |            INDEX UNIQUE SCAN            | PK_CELLDEF                 |     1 |       |     0   (0)| 00:00:01 |
    |  88 |        TABLE ACCESS BY INDEX ROWID      | CELLDEF                    |     1 |    33 |     1   (0)| 00:00:01 |
    |* 89 |         INDEX UNIQUE SCAN               | PK_CELLDEF                 |     1 |       |     0   (0)| 00:00:01 |
    |  90 |       BUFFER SORT                       |                            |     1 |    17 |   122   (2)| 00:00:02 |
    |  91 |        VIEW                             |                            |     1 |    17 |     2   (0)| 00:00:01 |
    |  92 |         TABLE ACCESS FULL               | SYS_TEMP_0FD9D9B53_2EBE182 |     1 |    10 |     2   (0)| 00:00:01 |
    |  93 |      TABLE ACCESS BY INDEX ROWID        | APPUSAGEACCESS             |     1 |    17 |     1   (0)| 00:00:01 |
    |* 94 |       INDEX UNIQUE SCAN                 | AK_APPUSAGEACCESS          |     1 |       |     0   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
       3 - filter("TAXGROUP_DELETE_IND"='N' AND "TAXGROUP_ACTIVE_IND"='A')
       4 - access("TAXGROUP_CODE"='TAXGROUP2')
      13 - filter("TGI"."HYPERIONBASE_ID" IS NOT NULL)
      14 - access("TG"."TAXGROUP_CODE"="TGI"."TAXGROUP_CODE")
      15 - access("TGI"."LEGALENTITY_ID"="OU"."ORGUNIT_ID" AND "TGI"."HYPERIONBASE_ID"="OU"."HYPERIONBASE_ID")
      21 - filter("TGI"."HYPERIONBASE_ID" IS NULL)
      22 - access("TG"."TAXGROUP_CODE"="TGI"."TAXGROUP_CODE")
      23 - access("TGI"."LEGALENTITY_ID"="OU"."ORGUNIT_ID")
      25 - access("APPUSAGE_CODE"='CONSOLIDATION')
      27 - filter("FD"."FIELDDATA_VALUE"=CASE INSTR("FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(164415),':') WHEN 0
                  THEN "FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(164415) ELSE
                  SUBSTR("FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(164415),1,INSTR("FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"(16441
                  5),':')-1) END )
      33 - access("LE_HB"."LEGALENTITY_ID"="FD"."LEGALENTITY_ID" AND
                  "LE_HB"."HYPERIONBASE_ID"="FD"."HYPERIONBASE_ID")
      39 - filter("FDK"."RN"=1)
      40 - filter(ROW_NUMBER() OVER ( PARTITION BY "CD"."CELLDEF_ID","FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"("FD"
                  ."FIELDDATA_GROUP_SEQUENCE") ORDER BY "FD"."FIELDDATA_GROUP_SEQUENCE")<=1)
      44 - access("GRS"."FD_GRPSEQ"="FD"."FIELDDATA_PARENT_ROW_SEQUENCE" AND
                  "GRS"."PRS_KEY"="FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"("FD"."FIELDDATA_PARENT_ROW_SEQUENCE"))
      45 - filter("FD"."FIELDDATA_DELETE_IND"='N')
      48 - access("TD"."TABLEDEF_ID"=2265)
      51 - access("LE_HB"."LEGALENTITY_ID"="FD"."LEGALENTITY_ID" AND
                  "LE_HB"."HYPERIONBASE_ID"="FD"."HYPERIONBASE_ID")
      55 - access("FD"."FIELDDATA_ID"="TC"."FIELDDATA_ID")
      56 - filter("CD"."TABLEDEF_ID"=2265 AND "CD"."CELLDEF_KEY_IND"='Y')
      57 - access("TC"."CELLDEF_ID"="CD"."CELLDEF_ID")
      61 - access("FDK"."CELLDEF_ID"="CD"."CELLDEF_ID")
      66 - access("AUA"."APPUSAGE_CODE"="AU"."APPUSAGE_CODE" AND "CD"."CELLDEF_ID"="AUA"."CELLDEF_ID")
      74 - access("GRS"."FD_GRPSEQ"="FD"."FIELDDATA_PARENT_ROW_SEQUENCE" AND
                  "GRS"."PRS_KEY"="FEDTAXPK_PKG"."GETFIELDDATAGROUPSEQKEY"("FD"."FIELDDATA_PARENT_ROW_SEQUENCE"))
      75 - filter("FD"."FIELDDATA_DELETE_IND"='N')
      78 - access("TD"."TABLEDEF_ID"=2265)
      81 - access("LE_HB"."LEGALENTITY_ID"="FD"."LEGALENTITY_ID" AND
                  "LE_HB"."HYPERIONBASE_ID"="FD"."HYPERIONBASE_ID")
      85 - access("FD"."FIELDDATA_ID"="TC"."FIELDDATA_ID")
      86 - filter("CD"."TABLEDEF_ID"=2265 AND "CD"."CELLDEF_ADJUSTABLE_IND"='Y')
      87 - access("TC"."CELLDEF_ID"="CD"."CELLDEF_ID")
      89 - access("FDA"."CELLDEF_ID"="CD"."CELLDEF_ID")
      94 - access("AUA"."APPUSAGE_CODE"="AU"."APPUSAGE_CODE" AND "CD"."CELLDEF_ID"="AUA"."CELLDEF_ID")

  • Create, Update & Save Functions

    Hi All,
    This is my code for the requirement to print sales order in ALV Grid Format using OOPS concept.
    Please tell me how i should add select button to the ALV Grid in the first column.
    Also when i click on CREATE button a new blank line should be added to the alv grid.
    when i click on UPDATE button the selected row should become editable & when i click on save then my Ztable should be update with the new values and all the changes made.
    The Ztable has fields as of the IT_FIANL table.
    I have gone through many links regarding this topic but cant implement it in my code.
    REPORT  z12darp_shad_so_alv_oops
            MESSAGE-ID z12darp1.
    *Class definition for handling double click
    CLASS event_class DEFINITION DEFERRED.
    *Class definition for ALV toolbar
    CLASS lcl_alv_toolbar   DEFINITION DEFERRED.
    *AUTHOR: Darpana. Ahire
    *DATE: 28/11/2008
    *DESCRIPTION: To printsales order as Interactive ALV using OOPS concept.
    *&               D A T A   D E C L R A T I O N
    type-pools: icon.
    INCLUDE z12darp_alv_oops.
    data: ok_code_2008 like sy-ucomm.
    *&  Include           Z12DARP_ALV_OOPS
    *Author: Darpana. Ahire
    *Date: 28/11/2008
    *Description: ALV Grid Using OOPS concept.
    tables: z12Darp_final.
    types: begin of ty_vbak,
             vbeln   type   vbeln_va,
             erdat   type   erdat,
             vkorg   type   vkorg,
             spart   type   spart,
          end of ty_vbak.
    types: begin of ty_vbap,
             vbeln   type   vbeln_va,
             posnr   type   posnr_va,
             matnr   type   matnr,
             netpr   type   netpr,
             netwr   type   netwr_ap,
           end of ty_vbap.
    types: begin of ty_final,
             vbeln   type   vbeln_va,
             erdat   type   erdat,
             vkorg   type   vkorg,
             spart   type   spart,
             posnr   type   posnr_va,
             matnr   type   matnr,
             netpr   type   netpr,
             netwr   type   netwr_ap,
           end of ty_final.
    data: wa_vbak   type   ty_vbak,
          wa_vbap   type   ty_vbap,
          wa_final  type   ty_final.
    data: it_vbak   type   standard table of   ty_vbak,
          it_vbap   type   standard table of   ty_vbap,
          it_final  type   standard table of   ty_final.
    data: v_vbeln   type   vbeln_va.
    data: cust   type   ref to     cl_gui_custom_container,
          alv    type   ref to     cl_gui_alv_grid,
          event_receiver TYPE REF TO event_class.
    data: wa_fcat       type    lvc_s_fcat,
          it_fcat       type    lvc_t_fcat,
          wa_layout     type    lvc_s_layo.
    *Declaration for toolbar buttons
    DATA : ty_toolbar TYPE stb_button.
    data: c_alv_toolbar    TYPE REF TO lcl_alv_toolbar.      "Alv toolbar
    *&               S E L E C T I O N     S C R E E N
    SELECT-OPTIONS: ss_vbeln FOR v_vbeln.
    *&                 I N I T I A L I Z A T I O N
    INITIALIZATION.
      PERFORM initial.
    *&               A T   S E L E C T I O N - S C R E E N
    AT SELECTION-SCREEN.
      PERFORM at_sel_scr.
    *&            S T A R T - O F - S E L E C T I O N
    START-OF-SELECTION.
      PERFORM sel_records.
      PERFORM join_tables.
      PERFORM alv_output.
    * CLASS lcl_event_receiver DEFINITION
    CLASS event_class DEFINITION.
    *Handling double click
      PUBLIC SECTION.
      METHODS:
        handle_double_click
        FOR EVENT double_click OF cl_gui_alv_grid
        IMPORTING e_row e_column.
    ENDCLASS. "lcl_event_receiver DEFINITION
    * CLASS lcl_event_receiver IMPLEMENTATION
    CLASS event_class IMPLEMENTATION.
    METHOD handle_double_click.
      case e_column.
        when 'MATNR'.
          read table it_final into wa_final index e_row-index.
          set parameter id 'MAT' field wa_final-matnr.
          call transaction 'MM03' and skip first screen.
       endcase.
    ENDMETHOD.           "handle_double_click
    endclass.
    *       CLASS lcl_alv_toolbar DEFINITION
    *       ALV event handler
    CLASS lcl_alv_toolbar DEFINITION.
      PUBLIC SECTION.
    *Event for toolbar
        on_toolbar
           FOR EVENT toolbar
           OF  cl_gui_alv_grid
           IMPORTING e_object e_interactive,
      handle_user_command
            for event user_command of cl_gui_alv_grid
                importing e_ucomm.
    endclass.
    *       CLASS lcl_alv_toolbar IMPLEMENTATION
    *       ALV event handler
    CLASS lcl_alv_toolbar IMPLEMENTATION.
    METHOD on_toolbar.
    *   Add customized toolbar buttons.
    *   variable for Toolbar Button
        clear ty_toolbar.
        ty_toolbar-icon      =  icon_create.
        ty_toolbar-butn_type = 0.
        ty_toolbar-text = 'CREATE'.
        APPEND ty_toolbar TO e_object->mt_toolbar.
        clear ty_toolbar.
        ty_toolbar-icon      =  icon_change.
        ty_toolbar-butn_type = 0.
        ty_toolbar-text = 'UPDATE'.
        APPEND ty_toolbar TO e_object->mt_toolbar.
        clear ty_toolbar.
        ty_toolbar-icon      =  icon_system_save.
        ty_toolbar-butn_type = 0.
        ty_toolbar-text = 'SAVE'.
        APPEND ty_toolbar TO e_object->mt_toolbar.
    ENDMETHOD.                    "on_toolbar
    method handle_user_command.
    case e_ucomm.
        when 'CREATE'.
        when 'UPDATE'.
    endcase.
    endmethod.                           "handle_user_command
    ENDCLASS.            "lcl_event_receiver IMPLEMENTATION
    *&      Module  STATUS_2008  OUTPUT
    *       text
    MODULE status_2008 OUTPUT.
      SET PF-STATUS 'MENU1'.
      SET TITLEBAR 'TITLE1'.
    ENDMODULE.                 " STATUS_2008  OUTPUT
    *&      Module  alv_display  OUTPUT
    *       text
    MODULE alv_display OUTPUT.
      IF cust IS INITIAL.
    *    Creating object of container
        CREATE OBJECT cust
        EXPORTING
          container_name              = 'CUSTOM'.
    *    Creating object of alv
        CREATE OBJECT alv
          EXPORTING
            i_parent          = cust.
    ** create ALV event handler
    *  CREATE OBJECT c_alv_toolbar
    *    EXPORTING
    *      io_alv_grid = alv.
    create object c_alv_toolbar.
    * Register event handler
      SET HANDLER c_alv_toolbar->on_toolbar FOR alv.
      set handler c_alv_toolbar->handle_user_command for alv.
    *    alv layout
        PERFORM alv_layout.
    *    alv field catalogue
        PERFORM fieldcatalog_display.
    *    Displaying the ALV grid
        CALL METHOD alv->set_table_for_first_display(
          EXPORTING
            is_layout                     = wa_layout
          CHANGING
            it_outtab                     = it_final
            it_fieldcatalog               = it_fcat ).
    *Create object of the event class and setting handler for double click
        CREATE OBJECT event_receiver.
        SET HANDLER event_receiver->handle_double_click FOR alv.
    ENDIF.
    ENDMODULE.                 " alv_display  OUTPUT
    *&      Module  USER_COMMAND_2008  INPUT
    *       text
    module USER_COMMAND_2008 input.
      case ok_code_2008.
        when 'EXT'.
          leave program.
        when 'BCK'.
          leave to screen 0.
        when 'UP'.
          leave program.
      endcase.
    endmodule.                 " USER_COMMAND_2008  INPUT
    *&                E N D   O F   M A I N   P R O G R A M
    *&      Form  initial
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM initial .
      CLEAR: wa_vbak,
             wa_vbap,
             wa_final.
      REFRESH: it_vbak,
               it_vbap,
               it_final.
    ENDFORM.                    " initial
    *&      Form  at_sel_scr
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM at_sel_scr .
      SELECT vbeln
        INTO TABLE it_vbak
        FROM vbak
        WHERE vbeln IN ss_vbeln.
      IF sy-subrc <> 0.
        MESSAGE e000.
      ENDIF.
    ENDFORM.                    " at_sel_scr
    *&      Form  sel_records
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM sel_records .
      SELECT vbeln
             erdat
             vkorg
             spart
      INTO TABLE it_vbak
      FROM vbak
      WHERE vbeln IN ss_vbeln.
      IF sy-subrc <> 0.
        MESSAGE e000.
      ENDIF.
      SELECT vbeln
             posnr
             matnr
             netpr
             netwr
      INTO TABLE it_vbap
      FROM vbap
      FOR ALL ENTRIES IN it_vbak
      WHERE vbeln = it_vbak-vbeln.
      IF sy-subrc <> 0.
        MESSAGE e000.
      ENDIF.
    ENDFORM.                    " sel_records
    *&      Form  join_tables
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM join_tables .
      SORT it_vbak BY vbeln.
      SORT it_vbap BY vbeln posnr.
      LOOP AT it_vbap INTO wa_vbap.
        READ TABLE it_vbak INTO wa_vbak WITH KEY vbeln = wa_vbap-vbeln
        BINARY SEARCH.
        wa_final-vbeln = wa_vbak-vbeln.
        wa_final-erdat = wa_vbak-erdat.
        wa_final-vkorg = wa_vbak-vkorg.
        wa_final-spart = wa_vbak-spart.
        wa_final-posnr = wa_vbap-posnr.
        wa_final-matnr = wa_vbap-matnr.
        wa_final-netpr = wa_vbap-netpr.
        wa_final-netwr = wa_vbap-netwr.
        APPEND wa_final TO it_final.
        CLEAR wa_final.
      ENDLOOP.
    ENDFORM.                    " join_tables
    *&      Form  alv_output
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM alv_output .
      CALL SCREEN 2008.
    ENDFORM.                    " alv_output
    *&      Form  alv_layout
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM alv_layout .
      wa_layout-grid_title = 'SALES ORDER'.
      wa_layout-zebra = 'X'.
    ENDFORM.                    " alv_layout
    *&      Form  fieldcatalog_display
    *       text
    *  -->  p1        text
    *  <--  p2        text
    FORM fieldcatalog_display .
    *  IT_FINAL-VBELN.                    SALES ORDER NUMBER
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='2'.
      wa_fcat-fieldname ='VBELN'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = 'X'.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='SALES ORDER NO.'.
      wa_fcat-outputlen   = 15.
      wa_fcat-ref_table ='VBAK'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-POSNR.                    SALES ITEM NUMBER
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='3'.
      wa_fcat-fieldname ='POSNR'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = 'X'.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='SALES ITEM NO'.
      wa_fcat-outputlen   = 15.
      wa_fcat-ref_table ='VBAP'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-ERDAT.                    DATE ON WHICH DOCUMENT WAS CREATED
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='4'.
      wa_fcat-fieldname ='ERDAT'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = ' '.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='DATE OF CREATION'.
      wa_fcat-outputlen   = 10.
      wa_fcat-ref_table ='VBAK'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-VKORG.                    SALES ORGANIZATION
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='5'.
      wa_fcat-fieldname ='VKORG'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = ' '.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='SALES ORG'.
      wa_fcat-outputlen   = 10.
      wa_fcat-ref_table ='VBAK'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-SPART.                    DIVISION
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='6'.
      wa_fcat-fieldname ='SPART'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = ' '.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='DIVISION'.
      wa_fcat-outputlen   = 10.
      wa_fcat-ref_table ='VBAK'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-MATNR.                    MATERIAL NUMBER
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='7'.
      wa_fcat-fieldname ='MATNR'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = ' '.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='MATERIAL NUMBER'.
      wa_fcat-outputlen   = 20.
      wa_fcat-ref_table ='VBAP'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-NETPR.                    NET PRICE
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='8'.
      wa_fcat-fieldname ='NETPR'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = ' '.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='NET PRICE'.
      wa_fcat-outputlen   = 15.
      wa_fcat-ref_table ='VBAP'.
      APPEND wa_fcat TO it_fcat.
    *  IT_FINAL-NETWR.                    NAET VALUE
      CLEAR wa_fcat.
      wa_fcat-col_pos  ='9'.
      wa_fcat-fieldname ='NETWR'.
      wa_fcat-tabname  ='IT_FINAL'.
      wa_fcat-key      = ' '.
      wa_fcat-just     = 'L'.
      wa_fcat-hotspot  = ' '.
      wa_fcat-lzero    ='X'.
      wa_fcat-seltext ='NET VALUE'.
      wa_fcat-outputlen   = 15.
      wa_fcat-ref_table ='VBAP'.
      APPEND wa_fcat TO it_fcat.
    ENDFORM.                    " fieldcatalog_display
    Regards,
    Darpana.
    Edited by: Darpana Ahire on Dec 3, 2008 7:10 AM
    Edited by: Matt on Dec 4, 2008 12:04 PM - added  tags

    im99_chs wrote:
    I have created a package with some functions in it.Keep in mind that these functions requires PL/SQL code to be executed. Thus it needs a context switch from the SQL engine (executing your view code) to the PL/SQL engine (to do the function call).
    This may work fine for smaller data sets. But it does not scale well as context switches are expensive operations with inherent latency. The more switches there are, the bigger the execution time chunk required for context switching.
    The ideal is to rather use SQL to perform the work of the function. SQL code can implement if-then-else logic via the DECODE() SQL function and SQL CASE command. Analytical functions can be used for complex aggregation and calculation.
    If a user define (PL/SQL) function is needed, then ensure that the function is as fast as possible (minimal moving parts), and consider defining it as a deterministic function if the same input always produces the same output.

  • Using User Defined Function is SQL

    Hi
    I did the following test to see how expensive it is to use user defined functions in SQL queries, and found that it is really expensive.
    Calling SQRT in SQL costs less than calling a dummy function that just returns
    the parameter value; this has to do with context switchings, but how can we have
    a decent performance compared to Oracle provided functions?
    Any comments are welcome, specially regarding the performance of UDF in sql
    and for solutions.
    create or replace function f(i in number) return number is
    begin
      return i;
    end;
    declare
      l_start   number;
      l_elapsed number;
      n number;
    begin
      select to_char(sysdate, 'sssssss')
        into l_start
        from dual;
      for i in 1 .. 20 loop
        select max(rownum)
          into n
          from t_tdz12_a0090;
      end loop;
      select to_char(sysdate, 'sssssss') - l_start
        into l_elapsed
        from dual;
      dbms_output.put_line('first: '||l_elapsed);
      select to_char(sysdate, 'sssssss')
        into l_start
        from dual;
      for i in 1 .. 20 loop
        select max(sqrt(rownum))
          into n
          from t_tdz12_a0090;
      end loop;
      select to_char(sysdate, 'sssssss') - l_start
        into l_elapsed
        from dual;
      dbms_output.put_line('second: '||l_elapsed);
      select to_char(sysdate, 'sssssss')
        into l_start
        from dual;
      for i in 1 .. 20 loop
        select max(f(rownum))
          into n
          from t_tdz12_a0090;
      end loop;
      select to_char(sysdate, 'sssssss') - l_start
        into l_elapsed
        from dual;
      dbms_output.put_line('third: '||l_elapsed);
    end;
    Results:
       first: 303
       second: 1051
       third: 1515
    Kind regards
    Taoufik

    I find that inline SQL is bad for performance but
    good to simplify SQL. I keep thinking that it should
    be possible somehow to use a function to improve
    performance but have never seen that happen.inline SQL is only bad for performance if the database design (table structure, indexes etc.) is poor or the way the SQL is written is poor.
    Context switching between SQL and PL/SQL for a User defined function is definitely a way to slow down performance.
    Obviously built-in Oracle functions are going to be quicker than User-defined functions because they are written into the SQL and PL/SQL engines and are optimized for the internals of those engines.
    There are a few things you can do to improve function
    performance, shaving microseconds off execution time.
    Consider using the NOCOPY hints for your parameters
    to use pointers instead of copying values. NOCOPY
    is a hint rather than a directive so it may or may
    not work. Optimize any SQL in the called function.
    Don't do anything in loops that does not have to be
    done inside a loop.Well, yes, but it's even better to keep all processing in SQL where possible and only resort to PL/SQL when absolutely necessary.
    The on-line documentation has suggested that using a
    DETERMINISTIC function can improve performance but I
    have not been able to demonstrate this and there are
    notes in Metalink suggesting that this does not
    happen. My experience is that DETERMINISTIC
    functions always get executed. There's supposed to
    be a feature in 11g that acually caches function
    return values.Deterministic functions will work well if used in conjunction with a function based index. That can improve access times when querying data on the function results.
    You can use DBMS_PROFILER to get run-time statistics
    for each line of your function as it is executed to
    help tune it.Or code it as SQL. ;)

  • Function and packages

    Hi friends ,
    I have a requirement where in i need to decode values from my source table while inserting them into my target table. I usually do my task by making functions (don't use case and decode) . My first question is
    1) Is using function to accomplish such tasks is good.I have numerous of such conversion requirement .
    2)Clubbing subprograms togther into packages is a good habit .But what should be the number of such sub programs .Can i club togther 100 of such functions togther (an average function is of 50 lines) ? If not what should be the segregation thoughts?
    3)Are the inbuilt oracle functions like sqrt,length etc deterministic ?
    This code represents a typical requirement of mine where in I map my source country name into target's
    country id while migrating my data from the source to the target .
    create table source
    emp_id number,
    empname varchar2(100),
    sal number,
    country varchar2(100)
    insert into source values (1,'ALEX',1000,'US');
    Insert into source values (2,'RAHUL',2000,'IND');
    Insert into source values (3,'KARTIK',3000,'IND');
    Insert into source values (4,'SHADOW',5000,'US');
    insert into source values(5,'LOUI',1500,'JAP');
    Create table source_country_code
    country varchar2(100),
    abbrv  varchar2(100),
    area number,
    climate varchar2(100)
    insert into source_country_code values ('UNITED STATES','US',10000,'COLD');
    insert into source_country_code values ('INDIA','IND',100000,'HOT');
    insert into source_country_code values ('JAPAN','JAP',1000000,'MODERATE');
    Create table target_country_code
    country_id number,
    descr  varchar2(100),
    density number,
    weather varchar2(100)
    insert into target_country_code values (101,'this is descrition txt 1',1001,'COLD');
    insert into target_country_code values (102,'this is descrition txt 2',1001,'HOT');
    insert into target_country_code values (103,'this is descrition txt 3',1001,'MODERATE');
    create table target
    emp_id number,
    empname varchar2(100),
    sal number,
    country_id number
    );i am typically making functions for such kind of mappings .I have numerous of such requirements as stated above and the
    cardinality of the data is high .
    create or replace function transform (in_src_country varchar2) return number deterministic
    as
    l_country_id number;
    l_climate varchar2(1000);
    begin
    select climate into l_climate from source_country_code
       where upper(abbrv)=upper(in_src_country);
    select country_id into l_country_id
    from target_country_code
    where upper(weather)=upper(l_climate);
    return(l_country_id);
    exception
    when no_data_found then
    return null;
    end;final step ,
    so ,what i usually do is
    insert into target
    select emp_id,empname,sal,transform(country) from source;
    Thanks as always,
    Rahul
    Edited by: Rahul K on Jun 5, 2013 10:51 AM

    Rahul  K wrote:
    Hi friends ,
    I have a requirement where in i need to decode values from my source table while inserting them into my target table. I usually do my task by making functions (don't use case and decode) . My first question is
    1) Is using function to accomplish such tasks is good.I have numerous of such conversion requirement .Not really. If the functions are sufficiently complex then sometimes there's no way around it. However you're going to pay the price if you try to add this to a SQL query (your query won't scale in the least).
    Rahul  K wrote:
    2)Clubbing subprograms togther into packages is a good habit .But what should be the number of such sub programs .Can i club togther 100 of such functions togther (an average function is of 50 lines) ? If not what should be the segregation thoughts?Yeah, put as many as makes sense. Generally you would want to separate them in some logical fashion, by business function, or some other convention.
    Rahul  K wrote:
    3)Are the inbuilt oracle functions like sqrt,length etc deterministic ? http://docs.oracle.com/cd/E11882_01/appdev.112/e25518/adfns_packages.htm#ADFNS386
    A deterministic function depends solely on the values passed into it as arguments and does not reference or modify the contents of package variables or the database or have other side-effects. Such a function produces the same result value for any combination of argument values passed into it.
    So yes. They are.
    Rahul  K wrote:
    This code represents a typical requirement of mine where in I map my source country name into target's
    country id while migrating my data from the source to the target .
    create table source
    emp_id number,
    empname varchar2(100),
    sal number,
    country varchar2(100)
    insert into source values (1,'ALEX',1000,'US');
    Insert into source values (2,'RAHUL',2000,'IND');
    Insert into source values (3,'KARTIK',3000,'IND');
    Insert into source values (4,'SHADOW',5000,'US');
    insert into source values(5,'LOUI',1500,'JAP');
    Create table source_country_code
    country varchar2(100),
    abbrv  varchar2(100),
    area number,
    climate varchar2(100)
    insert into source_country_code values ('UNITED STATES','US',10000,'COLD');
    insert into source_country_code values ('INDIA','IND',100000,'HOT');
    insert into source_country_code values ('JAPAN','JAP',1000000,'MODERATE');
    Create table target_country_code
    country_id number,
    descr  varchar2(100),
    density number,
    weather varchar2(100)
    insert into target_country_code values (101,'this is descrition txt 1',1001,'COLD');
    insert into target_country_code values (102,'this is descrition txt 2',1001,'HOT');
    insert into target_country_code values (103,'this is descrition txt 3',1001,'MODERATE');
    create table target
    emp_id number,
    empname varchar2(100),
    sal number,
    country_id number
    );i am typically making functions for such kind of mappings .I have numerous of such requirements as stated above and the
    cardinality of the data is high .
    create or replace function transform (in_src_country varchar2) return number deterministic
    as
    l_country_id number;
    l_climate varchar2(1000);
    begin
    select climate into l_climate from source_country_code
    where upper(abbrv)=upper(in_src_country);
    select country_id into l_country_id
    from target_country_code
    where upper(weather)=upper(l_climate);
    return(l_country_id);
    exception
    when no_data_found then
    return null;
    end;final step ,
    so ,what i usually do is
    insert into target
    select emp_id,empname,sal,transform(country) from source;
    Thanks as always,
    Rahul
    Edited by: Rahul K on Jun 5, 2013 10:51 AMYou would be much better (leaps and bounds better) off incorporating that logic directly into your SQL statement.
    Cheers,

  • Scaleability with Functions in SQL queries

    Hi,
    In one of our applications we have many views that use a packaged function in the where clause to filter data. This function uses a SYS_CONTEXT() to set and get values. There are couple of issues while using this approach:
    1/ The deterministic function doesn't allow any scability with PQ-server.
    2/ Another issue with this function and also the SYS_CONTEXT-function, they manuipulate the estimated CBO-statistics.
      CREATE TABLE TAB_I
      COLUMN1 NUMBER(16, 0) NOT NULL
    , COLUMN2 VARCHAR2(20)
    , CONSTRAINT TAB_I_PK PRIMARY KEY
        COLUMN1
      ENABLE
    CREATE TABLE TAB_V
        I_COL1     NUMBER(16,0) NOT NULL ENABLE,
        VERSION_ID NUMBER(16,0) NOT NULL ENABLE,
        CRE_DATIM TIMESTAMP (6) NOT NULL ENABLE,
        TERM_DATIM TIMESTAMP (6) NOT NULL ENABLE,
        VERSION_VALID_FROM DATE NOT NULL ENABLE,
        VERSION_VALID_TILL DATE NOT NULL ENABLE,
        CONSTRAINT TAB_V_PK PRIMARY KEY (I_COL1, VERSION_ID) USING INDEX NOCOMPRESS LOGGING ENABLE,
        CONSTRAINT COL1_FK FOREIGN KEY (I_COL1) REFERENCES TAB_I (COLUMN1) ENABLE
    CREATE OR REPLACE
    PACKAGE      app_bitemporal_rules IS
    FUNCTION f_knowledge_time RETURN TIMESTAMP DETERMINISTIC;
    END app_bitemporal_rules;
    create or replace
    PACKAGE BODY      app_bitemporal_rules IS
    FUNCTION f_knowledge_time RETURN TIMESTAMP DETERMINISTIC IS
    BEGIN
         RETURN TO_TIMESTAMP(SYS_CONTEXT ('APP_USR_CTX', 'KNOWLEDGE_TIME'),'DD.MM.YYYY HH24.MI.SSXFF');
    END f_knowledge_time;
    END app_bitemporal_rules;
    explain plan for select *
    FROM tab_i
    JOIN tab_v
    ON tab_i.column1 = tab_v.i_col1
    AND           app_bitemporal_rules.f_knowledge_time BETWEEN tab_v.CRE_DATIM AND tab_v.TERM_DATIM
    where tab_i.column1 = 11111;
    select * from table(dbms_xplan.display);
    Plan hash value: 621902595
    | Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT             |          |     1 |    95 |     5   (0)| 00:00:06 |
    |   1 |  NESTED LOOPS                |          |     1 |    95 |     5   (0)| 00:00:06 |
    |   2 |   TABLE ACCESS BY INDEX ROWID| TAB_I    |     1 |    25 |     1   (0)| 00:00:02 |
    |*  3 |    INDEX UNIQUE SCAN         | TAB_I_PK |     1 |       |     1   (0)| 00:00:02 |
    |*  4 |   TABLE ACCESS FULL          | TAB_V    |     1 |    70 |     4   (0)| 00:00:05 |
    Predicate Information (identified by operation id):
       3 - access("TAB_I"."COLUMN1"=11111)
       4 - filter("TAB_V"."I_COL1"=11111 AND
                  "TAB_V"."CRE_DATIM"<="APP_BITEMPORAL_RULES"."F_KNOWLEDGE_TIME"() AND
                  "TAB_V"."TERM_DATIM">="APP_BITEMPORAL_RULES"."F_KNOWLEDGE_TIME"())
    Note
       - 'PLAN_TABLE' is old version
       - dynamic sampling used for this statement (level=2)
    explain plan for select *
    FROM tab_i
    JOIN tab_v
    ON tab_i.column1 = tab_v.i_col1
    AND           '10-OCT-2011' BETWEEN tab_v.CRE_DATIM AND tab_v.TERM_DATIM
    where tab_i.column1 = 11111;
    select * from table(dbms_xplan.display);  
    Plan hash value: 621902595
    | Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT             |          |   256 | 24320 |     5   (0)| 00:00:06 |
    |   1 |  NESTED LOOPS                |          |   256 | 24320 |     5   (0)| 00:00:06 |
    |   2 |   TABLE ACCESS BY INDEX ROWID| TAB_I    |     1 |    25 |     1   (0)| 00:00:02 |
    |*  3 |    INDEX UNIQUE SCAN         | TAB_I_PK |     1 |       |     1   (0)| 00:00:02 |
    |*  4 |   TABLE ACCESS FULL          | TAB_V    |   256 | 17920 |     4   (0)| 00:00:05 |
    Predicate Information (identified by operation id):
       3 - access("TAB_I"."COLUMN1"=11111)
       4 - filter("TAB_V"."I_COL1"=11111 AND "TAB_V"."CRE_DATIM"<=TIMESTAMP'
                  2011-10-10 00:00:00.000000000' AND "TAB_V"."TERM_DATIM">=TIMESTAMP' 2011-10-10
                  00:00:00.000000000')
    Note
       - 'PLAN_TABLE' is old version
       - dynamic sampling used for this statement (level=2)   As can be seen in the second plan the cardinality has been guessed correctly, but not in the first case.
    I have also tried with:
    ASSOCIATE STATISTICS WITH packages app_bitemporal_rules DEFAULT COST (1000000/*246919*/,1000,0) DEFAULT SELECTIVITY 50;
    But, this just leads to a increased cost, but no change in cardinality.
    The (1) problem gets solved if I directly use "TO_TIMESTAMP(SYS_CONTEXT ('APP_USR_CTX', 'KNOWLEDGE_TIME'),'DD.MM.YYYY HH24.MI.SSXFF')" in the where clause. But am not able to find a solution for the (2) issue.
    Can you please help.
    Regards,
    Vikram R

    Hi Vikram,
    On the subject of using [url http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/statements_4006.htm#i2115932]ASSOCIATE STATISTICS, having done a little investigation on 11.2.0.2, I'm having trouble adjusting selectivity via "associate statististics ... default selectivity" but no problems with adjusting default cost.
    I've also tried to do the same using an interface type and am running into other issues.
    It's not functionality that I'm overly familiar with as I try to avoid/eliminate using functions in predicates.
    Further analysis/investigation required.
    Including test case of what I've done so far in case anyone else wants to chip in.
    SQL> select * from v$version;
    BANNER
    Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
    PL/SQL Release 11.2.0.2.0 - Production
    CORE    11.2.0.2.0      Production
    TNS for Linux: Version 11.2.0.2.0 - Production
    NLSRTL Version 11.2.0.2.0 - Production
    SQL> drop table t1;
    Table dropped.
    SQL>
    SQL> create table t1
      2  as
      3  select rownum col1
      4  from   dual
      5  connect by rownum <= 100000;
    Table created.
    SQL>
    SQL> exec dbms_stats.gather_table_stats(USER,'T1');
    PL/SQL procedure successfully completed.
    SQL>
    SQL> create or replace function f1
      2  return number
      3  as
      4  begin
      5   return 1;
      6  end;
      7  /
    Function created.
    SQL>
    SQL> create or replace function f2 (
      2   i_col1 in number
      3  )
      4  return number
      5  as
      6  begin
      7   return 1;
      8  end;
      9  /
    Function created.
    SQL> Created one table with 100000 rows.
    Two functions - one without arguments, one with (for later).
    With no associations:
    SQL> select * from user_associations;
    no rows selected
    SQL> Run a statement that uses the function:
    SQL> select count(*) from t1 where col1 >= f1;
      COUNT(*)
        100000
    SQL> select * from table(dbms_xplan.display_cursor);
    PLAN_TABLE_OUTPUT
    SQL_ID  gm7ppkbzut114, child number 0
    select count(*) from t1 where col1 >= f1
    Plan hash value: 3724264953
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |      |       |       |   139 (100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| T1   |  5000 | 25000 |   139  (62)| 00:00:01 |
    Predicate Information (identified by operation id):
       2 - filter("COL1">="F1"())
    19 rows selected.
    SQL> Shows that default selectivity of 5% for an equality predicate against function.
    Let's try to adjust the selectivity using associate statistics - the argument for selectivity should be a percentage between 0 and 100:
    (turning off cardinality feedback for clarity/simplicity)
    SQL> alter session set "_optimizer_use_feedback" = false;
    Session altered.
    SQL>
    SQL> ASSOCIATE STATISTICS WITH FUNCTIONS f1 default selectivity 100;
    Statistics associated.
    SQL> select count(*) from t1 where col1 >= f1;
      COUNT(*)
        100000
    SQL> select * from table(dbms_xplan.display_cursor);
    PLAN_TABLE_OUTPUT
    SQL_ID  gm7ppkbzut114, child number 1
    select count(*) from t1 where col1 >= f1
    Plan hash value: 3724264953
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |      |       |       |   139 (100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| T1   |  5000 | 25000 |   139  (62)| 00:00:01 |
    Predicate Information (identified by operation id):
       2 - filter("COL1">="F1"())
    19 rows selected.
    SQL> Didn't make any difference to selectivity.
    An excerpt from a 10053 trace file had the following:
    ** Performing dynamic sampling initial checks. **
    ** Dynamic sampling initial checks returning FALSE.
      No statistics type defined for function F1
      No default cost defined for function F1So, crucially what's missing here is a clause saying:
    No default selectivity defined for function F1But there's no other information that I could see to indicate why it should be discarded.
    Moving on, adjusting the cost does happen:
    SQL>exec spflush;
    PL/SQL procedure successfully completed.
    SQL> disassociate statistics from functions f1;
    Statistics disassociated.
    SQL>
    SQL> ASSOCIATE STATISTICS WITH FUNCTIONS f1 default selectivity 100 default cost (100,5,0);
    Statistics associated.
    SQL> select count(*) from t1 where col1 >= f1;
      COUNT(*)
        100000
    SQL> select * from table(dbms_xplan.display_cursor);
    PLAN_TABLE_OUTPUT
    SQL_ID  gm7ppkbzut114, child number 0
    select count(*) from t1 where col1 >= f1
    Plan hash value: 3724264953
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |      |       |       |   500K(100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| T1   |  5000 | 25000 |   500K  (1)| 00:41:41 |
    Predicate Information (identified by operation id):
       2 - filter("COL1">="F1"())
    19 rows selected.
    SQL> And we see the following in a 10053:
      No statistics type defined for function F1
      Default costs for function F1 CPU: 100, I/O: 5So, confirmation that default costs for function were found and applied but nothing else about selectivity again.
    I wondered whether the lack of arguments for function F1 made any difference, hence function F2.
    Didn't seem to:
    Vanilla:
    SQL> select count(*) from t1 where col1 >= f2(col1);
      COUNT(*)
        100000
    SQL>
    SQL> select * from table(dbms_xplan.display_cursor);
    PLAN_TABLE_OUTPUT
    SQL_ID  2wxw32wadgc1v, child number 0
    select count(*) from t1 where col1 >= f2(col1)
    Plan hash value: 3724264953
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |      |       |       |   139 (100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| T1   |  5000 | 25000 |   139  (62)| 00:00:01 |
    Predicate Information (identified by operation id):
       2 - filter("COL1">="F2"("COL1"))
    19 rows selected.
    SQL> Plus association:
    SQL>exec spflush;
    PL/SQL procedure successfully completed.
    SQL>
    SQL> associate statistics with functions f2 default selectivity 90 default cost (100,5,0);
    Statistics associated.
    SQL> select count(*) from t1 where col1 >= f2(col1);
      COUNT(*)
        100000
    SQL>
    SQL> select * from table(dbms_xplan.display_cursor);
    PLAN_TABLE_OUTPUT
    SQL_ID  2wxw32wadgc1v, child number 0
    select count(*) from t1 where col1 >= f2(col1)
    Plan hash value: 3724264953
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |      |       |       |   500K(100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| T1   |  5000 | 25000 |   500K  (1)| 00:41:41 |
    Predicate Information (identified by operation id):
       2 - filter("COL1">="F2"("COL1"))
    19 rows selected.
    SQL> Just to confirm associations:
    SQL> select * from user_associations;
    OBJECT_OWNER                   OBJECT_NAME                    COLUMN_NAME                    OBJECT_TY
    STATSTYPE_SCHEMA               STATSTYPE_NAME                 DEF_SELECTIVITY DEF_CPU_COST DEF_IO_COST DEF_NET_COST
    INTERFACE_VERSION MAINTENANCE_TY
    RIMS                           F2                                                            FUNCTION
                                                                               90          100           5
                    0 USER_MANAGED
    RIMS                           F1                                                            FUNCTION
                                                                              100          100           5
                    0 USER_MANAGED
    SQL> So.... started thinking about whether using an interface type would help?
    SQL> CREATE OR REPLACE TYPE test_stats_ot AS OBJECT
      2  (dummy_attribute NUMBER
      3  ,STATIC FUNCTION ODCIGetInterfaces (
      4     ifclist                OUT SYS.ODCIObjectList
      5   ) RETURN NUMBER
      6  ,STATIC FUNCTION ODCIStatsSelectivity (
      7      pred                   IN  SYS.ODCIPredInfo,
      8      sel                    OUT NUMBER,
      9      args                   IN  SYS.ODCIArgDescList,
    10      strt                   IN  NUMBER,
    11      stop                   IN  NUMBER,
    12      --i_col1                 in  NUMBER,
    13      env                    IN  SYS.ODCIEnv
    14   ) RETURN NUMBER
    15  --,STATIC FUNCTION ODCIStatsFunctionCost (
    16  --    func                   IN  SYS.ODCIPredInfo,
    17  --    cost                   OUT SYS.ODCICost,
    18  --    args                   IN  SYS.ODCIArgDescList,
    19  --    i_col1                 in  NUMBER,
    20  --    env                    IN  SYS.ODCIEnv
    21  -- ) RETURN NUMBER
    22  );
    23  /
    Type created.
    SQL> CREATE OR REPLACE TYPE BODY test_stats_ot
      2  AS
      3   STATIC FUNCTION ODCIGetInterfaces (
      4    ifclist                OUT SYS.ODCIObjectList
      5   ) RETURN NUMBER
      6   IS
      7   BEGIN
      8    ifclist := sys.odciobjectlist(sys.odciobject('SYS','ODCISTATS2'));
      9    RETURN odciconst.success;
    10   END;
    11   STATIC FUNCTION ODCIStatsSelectivity
    12   (pred                   IN  SYS.ODCIPredInfo,
    13    sel                    OUT NUMBER,
    14    args                   IN  SYS.ODCIArgDescList,
    15    strt                   IN  NUMBER,
    16    stop                   IN  NUMBER,
    17    --i_col1                 in  NUMBER,
    18    env                    IN  SYS.ODCIEnv)
    19   RETURN NUMBER
    20   IS
    21   BEGIN
    22     sel := 90;
    23     RETURN odciconst.success;
    24   END;
    25  -- STATIC FUNCTION ODCIStatsFunctionCost (
    26  --  func                   IN  SYS.ODCIPredInfo,
    27  --  cost                   OUT SYS.ODCICost,
    28  --  args                   IN  SYS.ODCIArgDescList,
    29  --  i_col1                 in  NUMBER,
    30  --  env                    IN  SYS.ODCIEnv
    31  -- ) RETURN NUMBER
    32  -- IS
    33  -- BEGIN
    34  --  cost := sys.ODCICost(10000,5,0,0);
    35  --  RETURN odciconst.success;
    36  -- END;
    37  END;
    38  /
    Type body created.
    SQL> But this approach is not happy - perhaps not liking the function with no arguments?
    SQL> disassociate statistics from functions f1;
    Statistics disassociated.
    SQL> ASSOCIATE STATISTICS WITH FUNCTIONS f1 USING test_stats_ot;
    Statistics associated.
    SQL> select count(*) from t1 where col1 >= f1;
    select count(*) from t1 where col1 >= f1
    ERROR at line 1:
    ORA-00604: error occurred at recursive SQL level 1
    ORA-06550: line 12, column 22:
    PLS-00103: Encountered the symbol "ÀÄ" when expecting one of the following:
    ) , * & = - + < / > at in is mod remainder not rem =>
    <an exponent (**)> <> or != or ~= >= <= <> and or like like2
    like4 likec between || multiset member submultiset
    SQL> So, back to F2 again (uncommenting argument i_col1 in ODCIStatsSelectivity):
    SQL> disassociate statistics from functions f1;
    Statistics disassociated.
    SQL> disassociate statistics from functions f2;
    Statistics disassociated.
    SQL> ASSOCIATE STATISTICS WITH FUNCTIONS f2 USING test_stats_ot;
    Statistics associated.
    SQL> select count(*) from t1 where col1 >= f2(col1);
      COUNT(*)
        100000
    SQL> select * from table(dbms_xplan.display_cursor);
    PLAN_TABLE_OUTPUT
    SQL_ID  2wxw32wadgc1v, child number 0
    select count(*) from t1 where col1 >= f2(col1)
    Plan hash value: 3724264953
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |      |       |       |   139 (100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| T1   |  5000 | 25000 |   139  (62)| 00:00:01 |
    Predicate Information (identified by operation id):
       2 - filter("COL1">="F2"("COL1"))
    19 rows selected.
    SQL> Nothing obviously happening.
    You'll note also in my interface type implementation that I commented out a declaration of ODCIStatsFunctionCost.
    This post is probably already too long already so I've skipped some of the detail.
    But when ODCIStatsFunctionCost was used with function F2, I presume I've made a mistake in the implementation because I had an error in the 10053 trace as follows:
      Calling user-defined function cost function...
        predicate: "RIMS"."F2"("T1"."COL1")
      declare
         cost sys.ODCICost := sys.ODCICost(NULL, NULL, NULL, NULL);
         arg0 NUMBER := null;
        begin
          :1 := "RIMS"."TEST_STATS_OT".ODCIStatsFunctionCost(
                         sys.ODCIFuncInfo('RIMS',
                                'F2',
                                NULL,
                                1),
                         cost,
                         sys.ODCIARGDESCLIST(sys.ODCIARGDESC(2, 'T1', 'RIMS', '"COL1"', NULL, NULL, NULL))
                         , arg0,
                         sys.ODCIENV(:5,:6,:7,:8));
          if cost.CPUCost IS NULL then
            :2 := -1.0;
          else
            :2 := cost.CPUCost;
          end if;
          if cost.IOCost IS NULL then
            :3 := -1.0;
          else
            :3 := cost.IOCost;
          end if;
          if cost.NetworkCost IS NULL then
            :4 := -1.0;
          else
            :4 := cost.NetworkCost;
          end if;
          exception
            when others then
              raise;
        end;
    ODCIEnv Bind :5 Value 0
    ODCIEnv Bind :6 Value 0
    ODCIEnv Bind :7 Value 0
    ODCIEnv Bind :8 Value 4
      ORA-6550 received when calling RIMS.TEST_STATS_OT.ODCIStatsFunctionCost -- method ignoredThere was never any such feedback about ODCIStatsSelectivity.
    So, in summary, more questions than answers.
    I'll try to have another look later.

  • Oracle result cache and functions

    Hi All,
    I am on 11.2 in Linux.
    I want to use Oracle's result cache to cache results of (user defined) functions, which we use in SELECT commands.
    My question is, does result caching work for deterministic and non-deterministic functions ?
    Just curious, how Oracle keeps track of changes being made which affect a function's return value?
    Thoughts please.
    Thanks in advance

    I want to ... cache results of (user defined) functions, which we use in SELECT commands.You have four choices:
    1. Subquery caching - (wrap function call in SELECT) useful for repeated function calls in a single SELECT
    2. Marking function as DETERMINISTIC - inconsistent results across versions, deterministic best reserved for function-based indexes only
    3. Result Cache
    4. Move function logic out of function and inline to the main SQL statement.
    The biggest downside of any function call that is inline to SQL is that it bypasses the read consistency mechanism, actually that's probably the second biggest downside. The biggest downside is normally that their misuse kills performance.
    If your function itself contains SQL then you should seriously reconsider whether you should be using a function.
    does result caching work for deterministic and non-deterministic functions ?Result cache knows nothing about determinism so yes it should be applied regardless.
    Oracle keeps track of changes being made which affect a function's return value?See v$result_cache_dependency.
    The mechanism is very blunt, there is no fine-grained tracking of data changes that may affect your result.
    It's as simple as function F1 relies on table T1. If the data in table T1 changes, invalidate the results in the result cache for F1.

  • Creating function-based indexes

    I'm trying to create a function-based index in one of the user's schemas and am getting an insufficient privilege error. Below are the examples:
    connect scott/tiger ;
    CREATE INDEX emp_ename_idx ON ename( emp ) ;
    Index created.
    CREATE INDEX upper_ename_idx ON ename( upper(ename)) ;
    ERROR at line1:
    ORA-01031: insufficient privileges
    The DBA granted the CREATE ANY INDEX privilege to user scott already. Any ideas???
    Thanks,
    SY

    Hi, all.
    I didn't hear about function-based index before, so I did some testing. Instead of using Oracle predefined functions (upper, lower, substr etc.), I created my own function and tried to create an index on it. I received an error that function is not deterministic. The definition of deterministic from Oracle docs:
    DETERMINISTIC
    This hint helps the optimizer avoid redundant function calls. If a stored function was called previously with the same arguments, the optimizer can elect to use the previous result. The function result should not depend on the state of session variables or schema objects. Otherwise, results might vary across calls. Only DETERMINISTIC functions can be called from a function-based index or a materialized view that has query-rewrite enabled.
    So, I put word deterministic in function declaration and everything works OK. Then I modified function to use some of the tables (I used tables across different schemas), recreated the index and it also worked fine.
    Question - is this statement correct: You can use schema objects in function which is in turn used for indexes as long as you put word deterministic in function declaration and all objects (function, index) will be valid, but ORACLE doesn't guarantee that result produced using that index will be correct?
    Thank you.

  • ORA-04091 (table string.string is mutating) and Function-Based Index

    I've encountered a problem with DELETEing from a table when that table has a function-based index on it. The following demonstrates this:
    SQL> CREATE OR REPLACE FUNCTION get_employee_location(p_empno IN number)
      2  RETURN varchar2
      3  DETERMINISTIC
      4  IS
      5  l_return_value   varchar2(20);
      6  BEGIN
      7  SELECT loc
      8  INTO   l_return_value
      9  FROM   dept
    10  WHERE  deptno = (SELECT
    11                   e.deptno
    12                   FROM emp e
    13                   WHERE empno = p_empno);
    14  return l_return_value;
    15  end;
    16  /
    Function created.
    SQL> create index location_idx on emp (get_employee_location(empno));
    Index created.
    SQL> delete from emp;
    delete from emp
    ERROR at line 1:
    ORA-04091: table SCOTT.EMP is mutating, trigger/function may not see it
    ORA-06512: at "SCOTT.GET_EMPLOYEE_LOCATION", line 7------------------------------------------------
    The question is: How can I successfully DELETE FROM emp but keep my function-based index in place?
    Thanks
    Andy

    'Being able to' is 'being able to', but
    it is dangerous to declare "DETERMINISTIC" for non-deterministic function.
    The following problem happens on non-deterministic function index.
    SQL> update dept set loc = 'NEWYORK' where deptno=10;
    1 row updated.
    SQL> commit;
    Commit complete.
    SQL> select * from emp where get_employee_location(deptno)='NEWYORK';
    no rows selected
    SQL> select * from dept;
        DEPTNO DNAME          LOC
            10 ACCOUNTING     NEWYORK
            20 RESEARCH       DALLAS
            30 SALES          CHICAGO
            40 OPERATIONS     BOSTON
    SQL> select empno,ename from emp where get_employee_location(deptno)='NEW YORK';
         EMPNO ENAME
          7782 CLARK
          7839 KING
          7934 MILLER
    SQL> select empno,ename,get_employee_location(deptno) from emp where deptno=10;
         EMPNO ENAME      GET_EMPLOYEE_LOCATION(DEPTNO)
          7782 CLARK
          7839 KING
          7934 MILLER
    SQL> select empno,ename,get_employee_location(deptno) from emp where get_employee_location(deptno)='NEW YORK';
         EMPNO ENAME      GET_EMPLOYEE_LOCATION(DEPTNO)
          7782 CLARK      NEW YORK
          7839 KING       NEW YORK
          7934 MILLER     NEW YORK
    SQL> drop index location_idx ;
    Index dropped.
    SQL> select empno,ename from emp where get_employee_location(deptno)='NEW YORK';
    no rows selected

  • Query result cache with functions

    Hi all,
    one of my colleagues has found a little bit weird behavior of a query result cache. He has set result_cache_mode = 'FORCE' (but it can be reproduced with a result_cache hint too) and suddenly functions called from the query get executed twice (for the first time) .
    An easy example:
    alter session set result_cache_mode = 'FORCE';
    create sequence test_seq;
    create or replace function test_f(i number)
    return number
    is                  
    begin
      dbms_output.put_line('TEST_F executed');
      --autonomous transaction or package variable can be used too
      return test_seq.nextval;
    end;
    prompt First call
    select test_f(1) from dual;
    prompt Second call
    select test_f(1) from dual;
    drop sequence test_seq;
    drop function test_f;
    First call
    TEST_F(1)
             2
    TEST_F executed
    TEST_F executed
    Second call
    TEST_F(1)
             1
    As you can see - for the first time the function is executed twice and return the value from the second execution. When I execute the query again it returns the value from the first execution... but it doesn't matter, problem is in the double execution. Our developers used to send emails via select (it's easier for them):
    select send_mail(...) from dual;
    ... and now the customers complains that they get emails twice
    And now the question - is there any way, hot to get rid of this behavior (without changing the parameter back or rewriting code)? I thought that the result cache is automatically disabled for non-deterministic functions...or is this an expected behavior?
    Thanks,
    Ivan

    Interesting.. you are right:
    SELECT /*+ RESULT_CACHE */ 'dog' FROM DUAL;
    And at the second execution:
    | Id  | Operation        | Name                       | Rows  | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT |                            |     1 |     2   (0)| 00:00:01 |
    |   1 |  RESULT CACHE    | cc5k01xyqz3ypf9t0j28r5gtd1 |       |            |          |
    |   2 |   FAST DUAL      |                            |     1 |     2   (0)| 00:00:01 |
    Hmmm..

Maybe you are looking for