I am having problems with the procedure; when starting for "large" sets (800+ parents, 1300 + children), it is very slow (30-60 seconds).
The main idea is to select all the parent records (and their corresponding child elements) that match certain search criteria, as well as 3 additional pieces of information that will need to be calculated.
My approach to the problem was
- to create your own record type with additional fields for calculated values.
- A reference to this type of record can then be passed to each function controlled by the main processing function.
- When a value is calculated for each parent record, bind it to the record.
Each procedure GET_PARENT_RECORDS and GET_CHILD_RECORDS is called once for each search, and each computational function is executed N times (where N is the number of parent and / or child records).
Question 1 : Is this the right approach? (weakly typed cursors, pipelined functions). If not, how can I approach this problem, assuming that I can redo it?
Question 2 : prohibition of full rewriting, is there something obvious that can be improved in the provided code?
Question 3 : Or something else may be wrong, because I notice that the same slow request returned after 20 seconds when I started the procedure several times?
Package definition
create or replace PACKAGE THIS_PKG AS Type parentCursor IS REF CURSOR; Type childCursor IS REF CURSOR; Type ParentRecordType IS RECORD ( other_columns, Extra_column_A, Extra_column_B, Extra_column_C, Row_num); --associative array TYPE ParentArray IS TABLE OF ParentRecordType; FUNCTION processParents( p IN THIS_PKG. parentCursor ) RETURN ParentArray PIPELINED ; FUNCTION countSomething(some paramsβ¦) RETURN INT; FUNCTION checkCondX (SomeParent IN ParentRecordType) RETURN VARCHAR2; FUNCTION checkCondY (SomeParent IN ParentRecordType) RETURN VARCHAR2; PROCEDURE GET_PARENT_RECORDS( other_parameters, Parents OUT THIS_PKG.parentCursor); PROCEDURE GET_CHILD_RECORDS( other_parameters, Children OUT THIS_PKG.childCursor); END THIS_PKG;
Packing body
-- omitted FUNCTION processParents( p IN THIS_PKG.parentCursor ) RETURN ParentArray PIPELINED IS out_rec ParentArray; someParent ParentRecordType; BEGIN LOOP FETCH p BULK COLLECT INTO out_rec LIMIT 100; FOR i IN 1 .. out_rec.COUNT LOOP out_rec(i).extra_column_A := countSomething (out_rec(i).field1, out_rec(i).field2); out_rec(i).extra_column_B := checkCondX(out_rec(i)); out_rec(i).extra_column_C := checkCondY(out_rec(i)); pipe row(out_rec(i)); END LOOP; EXIT WHEN p%NOTFOUND; END LOOP; RETURN; END processParents; PROCEDURE GET_PARENT_RECORDS( some_columns, Parents OUT THIS_PKG. parentCursor) IS BEGIN OPEN Parents FOR SELECT * FROM TABLE(processParents (CURSOR( SELECT * FROM ( --some select statement with quite a few where clause --to simulate dynamic search (from pre-canned search options) ) ))) abc WHERE abc.extra_column_C like '%xyz%' --(xyz is a user given value) ; END GET_PARENT_RECORDS;
Update Some research took place yesterday and came across the SQL Batch Task optimizer (from Toad). I plugged in the package and this is what I got.
Batch Optimizer Results 
Comprehensive request 
Problem request 