Home>Question Details



-- Thanks for the question regarding "sub-rotuines and their relationship with the WITH clause (in-line views)", version 11g

Submitted on 23-Oct-2009 13:32 Central time zone
Last updated 26-Oct-2009 15:34

You Asked

Hi Tom,

We have developed a rather quantitative process that spans seven functions (steps) within a single package.

The code contains only SQL statements. There are no temp table; no procedural code. Each function achieves a specific task, which has been comprehensively documented as a requirement. As such, each function is a delight to read, and maintain.

The entire code, across all functions, occupies approximately 14 pages of code. While we certainly could have compiled the code into one procedure, we chose to break the code down based upon a logical categorisation of the code. Good old modular programming! The application calls the initial function of the package and the final result set is returned. Results sets are made available between function N and function N + 1 by way of ref cursors - obviously.

I would like to understand if there would be a performance cost in using this approach, compared to a single procedure (14 pages long - so awful to maintain and test) but without the need to pass ref cursors between functions. In other words, how does the Oracle database handle ref cursors compared to inline views? It would be great if the performance difference was close to zero.

In SQL Server there are no ref cursors - obviously. When we first developed the above approach in SQL Server, we had to write the result set of each function to disk, and then read the results from disk again in the next function. This had a huge performance hit.

and we said...

... In other words, how does the Oracle database handle ref cursors compared to inline views? ....

I'm not sure how to answer this, because I cannot fathom where one would be used in place of the other.

a ref cursor is a handle to a result set, you have to fetch from it - you cannot do anything else.

an inline view is a set generated in a single sql statement, you don't fetch from it, it is used by the sql itself.

I cannot see how one would be substituted for the other.

I can say this - IF you are doing something like:

procedure foo( p_cursor in out sys_refcursor 
is
begin
    fetch p_cursor into record;
    loop
        exit when p_cursor%notfound;
        select ... where key = record.component;
        .....
        fetch p_cursor into record;
    end loop;
    close p_cursor;
end;



then, I would say you really - really - meant NOT to open the cursor in the calling function, you meant to just


for x in (select .... where key IN (that defining query))
loop
    ....
end;




So, I have a feeling - a big feeling - that you have tons of slow by slow code - doing things row by row - and would be better off taking a step back and asking yourself "how much of this procedural code can we DELETE forever by rolling tons of procedural code into a set based sql statement.


but, it is a feeling, I don't have anything to look at, I cannot tell what you are really doing.
Reviews    
5 stars Further explanation   October 26, 2009 - 9am Central time zone
Reviewer: Analyst from Melbourne
We are trying to efficiently pass result sets between functions. Perhaps ref cursor was the wrong 
concept to which to refer.

We have the following code conceptually:

Procedure A (inputParamter)
{
(several inline views)
Return a set called foo
}

Procedure B (ResultSet foo)
{
select ...
from foo
... (more SQL code)
Return result set called foo2
}

The result set foo2 is returned to the user.

Now, certainly we could create a single procedure that contains the SQL code from Procedure A and 
Procedure B. However, this is the wrong approach - of course. So, we would like to have one 
function that performs the work of Procedure A and returns a set, and another function that 
performs the work of Procedure B. The latter function would accept at input, the set produced from 
Procedure A, and return a result set.

I would like to understand the best way to implement this solution.


Followup   October 26, 2009 - 2pm Central time zone:

what is your concept of a result set then? give me a pared down snippet of actual code to review. I don't know what you are doing.


I don't know why A would be needed to procedure a set. If the set is the result of a sql query - A is not necessary or desired, so therefore, I think A must include procedural code and builds a collection - an array - but I don't really know what you mean.
3 stars RE: single procedure that contains the SQL code from Procedure A and Procedure B.   October 26, 2009 - 12pm Central time zone
Reviewer: Duke Ganote from Amelia, Ohio USA
Why not a single query that contains the SQL from Procedure A and Procedure B?

That's the mantra!
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:672724700346558185#6758131003460
56247


5 stars A rather involved process   October 26, 2009 - 2pm Central time zone
Reviewer: Analyst from Melbourne
""Why not a single query that contains the SQL from Procedure A and Procedure B?

That's the mantra! "

Of course. Where practical, all SQL code should be stored in one routine. However, my question is 
from the perspective of code maintenance.

If I were to amalgamate the code from all of the associated procedures that comprise the process in 
question, the procedure would contain no less that 5 or so pages of SQL code. There is NO 
procedural code. Now, I would rather not have a procedure of five pages.

Perhaps I was wrong - happy to admit so - in my use of the term procedure. Simply, I have a 
process. This process involves about 5 pages of code. The process can be said to comprise three key 
steps. I would like these steps to be maintained, ideally, as three routines. I would like to 
follow the same approach that you would in modular coding.



Followup   October 26, 2009 - 3pm Central time zone:

... the procedure would contain no less that 5 or
so pages of SQL code. ...

that is dandy. comment it well (and buy a bigger monitor - I have a really tall one I use)

You can also use views if approach to "modularize"

or with subquery factoring


with procedureA
as
(select ......),
procedureB
as
(select ..... ),
procedureC
as
(select .... ),
select from procedurea, procedureb, procedurec


and stick a form feed in a comment between each with.
3 stars That's a tall order...   October 27, 2009 - 7am Central time zone
Reviewer: Duke Ganote from Amelia, Ohio USA
While SQL is almost second nature to me, and my mother "tongue" of FORTRAN is but a wisp of memory, most of my annoyance is due not to SQL itself, but the number of columns on table.

Tall tables require a "tall monitor", if you're adhering to the convention of one-column-per-line, e.g.
SELECT ASL
     , ASL_DESCRIPTION
     , ADMITTED_STATUS
     , STATE_CD
     , COASTAL_PROXIMITY_TIER_NBR
     , period                  AS CURRENT_PERIOD
     , ALPHA_SORT
     , COASTAL_ASSESSABILITY_CD
     , measure_name            AS MEASUREMENT_NAME
     , total_measure_amt       AS TOTAL_MEASURE
     , assessed_measure_amt    AS ASSESSED_MEASURE
     , nonassessed_measure_amt AS NONASD_MEASURE
  FROM COASTAL_EXP_HIST
 WHERE period IN
          (ADD_MONTHS (TRUNC (SYSDATE, 'q'), -1)
         , ADD_MONTHS (TRUNC (SYSDATE, 'q'), -13)
          )

As Tom suggests, modularizing using "WITH subqueries" where possible, and comments where necessary, is the best approach I've found.

For example, here's just one section of a query I wrote to populate a reporting/summary table with 105 columns:
         -- ****************************************************
         -- Prior Current Month and Current Growth
         -- ****************************************************
       , SUM ( CASE WHEN Periods.CURRENT_FLAG = '12'
                    THEN exPERience.EARNED_PREMIUM
                END ) AS pcurr_EP
       , SUM ( CASE WHEN Periods.CURRENT_FLAG = '12'
                    THEN  exPERience.INCURRED_LOSS
                       +  exPERience.EARNED_PREMIUM
                          * (Agents.OVERHEAD_PCT / 100 )
                END ) AS pcurr_IL -- Incurred_Loss_with_ULAE
       , SUM ( CASE WHEN exPERience.NEW_RENEWAL_CD = 0
                     AND Periods.CURRENT_FLAG = '12'
                    THEN exPERience.NET_WRITTEN
                    ELSE 0
                END ) AS pCurr_New_WP
       , SUM ( CASE WHEN exPERience.NEW_RENEWAL_CD = 0
                     AND Periods.CURRENT_FLAG = 'Current'
                    THEN exPERience.NET_WRITTEN
                END )
         / NULLIF (
         SUM ( CASE WHEN exPERience.NEW_RENEWAL_CD = 0
                     AND Periods.CURRENT_FLAG = '12'
                    THEN exPERience.NET_WRITTEN
                END )
               , 0 )
         - 1 AS curr_new_WP_growth
       , SUM ( CASE WHEN (  Periods.CURRENT_FLAG = '12' )
                    THEN exPERience.NET_WRITTEN
                    ELSE 0
                END ) AS pCurr_total_WP
       , SUM ( CASE WHEN Periods.CURRENT_FLAG = 'Current'
                    THEN exPERience.NET_WRITTEN
                END )
         / NULLIF (
         SUM ( CASE WHEN Periods.CURRENT_FLAG = '12'
                    THEN exPERience.NET_WRITTEN
                END )
               , 0 )
         - 1 AS curr_total_WP_growth

105 columns? Yep, I wrote about it here:
http://it.toolbox.com/blogs/data-ruminations/the-absolutely-stunningly-beautiful-table-25899


Each section of SQL is "cohesive" (in the computer science sense)
http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29

and still fits on an ordinary monitor page.


Write a Review
 


All information and materials provided here are provided "as-is"; Oracle disclaims all express and implied warranties, including, the implied warranties of merchantability or fitness for a particular use. Oracle shall not be liable for any damages, including, direct, indirect, incidental, special or consequential damages for loss of profits, revenue, data or data use, incurred by you or any third party in connection with the use of this information or these materials.

About Oracle | Legal Notices and Terms of Use | Privacy Statement