Return data rows from a pl/sql block - oracle

I want to write pl/sql code which utilizes a Cursor and Bulk Collect to retrieve my data. My database has rows in the order of millions, and sometimes I have to query it to fetch nearly all records on client's request. I do the querying and subsequent processing in batches, so as to not congest the server and show incremental progress to the client. I have seen that digging down for later batches takes considerably more time, which is why I am trying to do it by way of cursor.
Here is what should be simple pl/sql around my main sql query:
declare
cursor device_row_cur
is
select /my_query_details/;
type l_device_rows is table of device_row_cur%rowtype;
out_entries l_device_rows := l_device_rows();
begin
open device_row_cur;
fetch device_row_cur
bulk collect into out_entries
limit 100;
close device_row_cur;
end;
I am doing batches of 100, and fetching them into out_entries. The problem is that this block compiles and executes just fine, but doesn't return the data rows it fetched. I would like it to return those rows just the way a select would. How can this be achieved? Any ideas?

An anonymous block can't return anything. You can assign values to a bind variable, including a collection type or ref cursor, inside the block. But the collection would have to be defined, as well as declared, outside the block. That is, it would have to be a type you can use in plain SQL, not something defined in PL/SQL. At the moment you're using a PL/SQL type that is defined within the block, and a variable that is declared within the block too - so it's out of scope to the client, and wouldn't be a valid type outside it either. (It also doesn't need to be initialised, but that's a minor issue).
Dpending on how it will really be consumed, one option is to use a ref cursor, and you can declare and display that through SQL*Plus or SQL Developer with the variable and print commands. For example:
variable rc sys_refcursor
begin
open :rc for ( select ... /* your cursor statement */ );
end;
/
print rc
You can do something similar from a client application, e.g. have a function returning a ref cursor or a procedure with an out parameter that is a ref cursor, and bind that from the application. Then iterate over the ref cursor as a result set. But the details depend on the language your application is using.
Another option is to have a pipelined function that returns a table type - again defined at SQL level (with create type) not in PL/SQL - which might consume fewer resources than a collection that's returned in one go.
But I'd have to question why you're doing this. You said "digging down for later batches takes considerably more time", which sounds like you're using a paging mechanism in your query, generating a row number and then picking out a range of 100 within that. If your client/application wants to get all the rows then it would be simpler to have a single query execution but fetch the result set in batches.
Unfortunately without any information about the application this is just speculation...

I studied this excellent paper on optimizing pagination:
http://www.inf.unideb.hu/~gabora/pagination/article/Gabor_Andras_pagination_article.pdf
I used technique 6 mainly. It describes how to limit query to fetch page x and onward. For added improvement, you can limit it further to fetch page x alone. If used right, it can bring a performance improvement by a factor of 1000.
Instead of returning custom table rows (which is very hard, if not impossible to interface with Java), I eneded up opening a sys_refcursor in my pl/sql which can be interfaced such as:
OracleCallableStatement stmt = (OracleCallableStatement) connection.prepareCall(sql);
stmt.registerOutParameter(someIndex, OracleTypes.CURSOR);
stmt.execute();
resultSet = stmt.getCursor(idx);

Related

Perfomance Out parameter vs Out system ref cursor Oracle Procedure

I have a Procedure in oracle with 12 parameters 4 of them are sys ref cursor. I am replace one cursor from my procedure using 8 more out parameters. Will there be any performance enhancement if use out parameters instead of out ref cursor.
A cursor can be thought of as a pointer to an area of memory within the database that contains a result set - it does not directly contain the results; so when you send a cursor you are just sending the pointer and then whatever user interface you are using will have to make additional round-trips to the database to use that cursor (pointer) to open the result set, fetch rows and then, when you are finished, close the cursor.
When you use an out parameter with individual values then the values can all be returned as the procedure terminates and no additional communication with the database is required.
Will there be any performance enhancement if use out parameters instead of out ref cursor.
So, yes, there may be a performance enhancement if you are returning multiple out parameters rather than a cursor which refers to a result set with a single row. However, as with all performance enhancements, you should profile the changes so that you can see the actual effect (which may be negligible).

Oracle: Using Procedure or Cursor to store a Select-Statement?

I have a PL/SQL package where i want to declare a select-statment which are used by different other Packages. So i see to ways. First way i define a cursor which can be called from other packages and store the select. Second way would be a procedure which stored the select.
Can someone tell me the advantages and disadvantages of each way? My Prof. say Cursor are old and statefull and noone use this today. My Chef tell me Cursor is faster to iterate and you can make Types of it.
Can someone tell me what's the best practice here?
For example:
CURSOR crs_active_customer IS
SELECT * FROM customer where status = 'active'
OR
PROCEDURE prc_getActiveCustomer IS
BEGIN
SELECT * FROM customer where status = 'active';
END prc_getActiveCustomer;
What is better way to store select-statements.
I would write a function that returns a new cursor instance every time you call it. A cursor variable in a package is actually a GLOBAL variable: you can have only one procedure at a time using it. This is probably the problem your professor is referring to.
Having a global cursor means that you will run into "cursor already open" errors if you write a a procedure that, while scanning the results of such cursor calls another function that internally needs to use the same cursor.
PL/SQL 101 to the rescue ! From Working with Cursors:
The central purpose of the Oracle PL/SQL language is to make it as easy and efficient as possible to query and change the contents of tables in a database. You must, of course, use the SQL language to access tables, and each time you do so, you use a cursor to get the job done.
So every time you have SQL in PL/SQL there will be a cursor. The next question is what kinds of cursors there is and when to use them. The above mentioned article touches also this topic.
You can also read the fine manual: Cursors
A cursor is a pointer to a private SQL area that stores information about processing a specific SELECT or DML statement.
And then carry on reading about implicit and explicit cursors.
Next find a better professor.

Getting error writing an anonymous block in TOAD DB2

I am new to DB2. I want to execute an anonymous black in toad.
BEGIN ATOMIC
DECLARE TEMP_SCHEMA VARCHAR(12) ;
SET TEMP_SCHEMA = 'SCHEMA1';
SELECT * FROM TEMP_SCHEMA.TABLE_NAME
WHERE 1=1
WITH UR;
END;
I am getting following error:
20159: [IBM][DB2/AIX64] SQL20159W The isolation clause is ignored because of the statement context.
Can you please help.
According to the documentation at https://www.ibm.com/support/knowledgecenter/en/SSMKHH_10.0.0/com.ibm.etools.mft.doc/ak04940_.htm?view=embed , "If ATOMIC is specified, only one instance of a message flow (that is, one thread) is allowed to execute the statements of a specific BEGIN ATOMIC... END statement (identified by its schema and label), at any one time. If no label is present, the behavior is as if a zero length label had been specified.
The BEGIN ATOMIC construct is useful when a number of changes need to be made to a shared variable and it is important to prevent other instances seeing the intermediate states of the data."
Using ATOMIC in a stored procedure means that your code will execute as a singleton, providing maximal isolation. That would be in direct conflict with your "WITH UR" isolation option. Even though you are using the ATOMIC keyword in a script, not in a stored procedure, DB2 still treats it as a single thread, so it will complain if you include query hints that attempt to lower the isolation level.
After removing the ATOMIC keyword, you are getting the token error because your SELECT * FROM TEMP_SCHEMA.TABLE_NAME
WHERE 1=1 statement is attempting to return a result set to Toad from inside a BEGIN block. Unfortunately, this is not possible in DB2. As soon as you have any procedural code, which forces you to utilize a BEGIN block, DB2 steadfastly refuses to return data to the client. The only way that I found to return results from inside a BEGIN block is to place the BEGIN block in a stored procedure, and then use a CURSOR to return the result set to Toad, e.g.,
BEGIN
DECLARE C1 CURSOR WITH RETURN WITH HOLD FOR SELECT * FROM .EMPLOYEE;
OPEN C1;
END;
Note that you must enclose the CURSOR code in an inner BEGIN block, which DB2 requires when sending a result set back to the client WITH HOLD.
If you want to return the value of a variable to Toad from your prototype stored procedure, you can use this approach:
BEGIN
DECLARE C1 CURSOR WITH RETURN WITH HOLD FOR
SELECT * FROM TABLE(SELECT * FROM (VALUES(<variable goes here>))
AS TEMP(<descriptive name for the variable goes here>)) AS TEMP1;
OPEN C1;
END;
To summarize, in order to use the Anonymous Block as a prototyping vehicle in a development tool such as Toad, you have to wrap it in a stored procedure if you want to return any results, and you must use a CURSOR embedded in an inner BEGIN block to do so. Its unfortunate that DB2 is so much more cumbersome than MS SQL Server in this regard.

UPDATE statement: Returning into refcursor

I have a query that updates a set of records based on specific criteria. I want to get columns of the result set of that update statement and pass it back in a refcursor.
I can get the result set by using RETURNING INTO, or in my case, RETURNING myrows BULK COLLECT INTO .... However, I'm not sure how to make this work with a cursor - you can't do an OPEN cursor FOR with an update statement.
I'm guessing there's a way to get the results of a RETURNING statement into my cursor. How can I do this?
Assuming that you have a SQL collection defined (rather than a PL/SQL collection), you should be able to
RETURNING my_column
BULK COLLECT INTO my_collection;
and then
OPEN p_rc
FOR SELECT *
FROM TABLE( my_collection );
Though that works, there are some caveats. If you expect the UPDATE to modify a large number of rows (or you expect many sessions to be running this code), storing all this data in a collection may consume a large amount of space in the PGA which may negatively impact performance. Reading a bunch of data into a collection just to send it all back to the SQL engine also tends to be a bit inelegant. And, as I said initially, this assumes that your collection is declared at the SQL level rather than being declared in PL/SQL.

Executing an Oracle stored procedure returning a REF CURSOR using SqlAlchemy

I have a stored procedure that I have defined in Oracle. In that procedure I need to return a recordset. To do this, I am using the SYS_REFCURSOR, which works great inside of Oracle (and with cx_Oracle, for that matter). In my application I am using SqlAlchemy scoped sessions, to support multi-threading.
How can I use the scoped session to return the REF CURSOR? The only way I have been able to get this to work is by declaring an out cursor with the cursor that is active in the session and then executing the stored procedure, like below:
sql = """
BEGIN
example('%s', '%s', '%s', :cur);
END;
""" % (cid, show, type)
conn = sa_tool.session.connection()
in_cur = conn._Connection__connection.cursor()
out_cur = conn._Connection__connection.cursor()
in_cur.execute(sql, cur=out_cur)
results = out_cur.fetchall()
Ideally, I would like to avoid using the connection object in this way, and execute the procedure while letting SqlAlchemy manage the cursors. If that is not possible, is there a reason that the fetch would take so long?
Thanks
I saw this question which was not answered and I decided to jump in. First of all, let me just say that for your scenario there is no better option than SYS_REFCURSOR. Of course, you have alternatives.
An Oracle Cursor is a memory area location where an instruction to execute a SQL statement is stored. A Ref cursor is just a pointer to the cursor location. SYS_REFCURSOR is an specific oracle defined typed of ref cursor. So when you return a SYS_REFCURSOR variable to a client, you are returning a pointer towards the memory location where the instruction to execute the SQL resides. Your client can now execute the instruction using the FETCH operation and get the rows. So this is the best possible way to return a result set to the client.
As an alternative, you might use a PIPELINED FUNCTION, but I can assure you that you won't get any better performance. AskTom has a great explanation about this comparison in this article
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9532870400346178516
Another scenario is whether you want to analyse where the time is consumed, either in the EXECUTE phase or in the FETCH one. If you have a huge time in FETCH, perhaps you might consider transfer the data in another way to the client. If you have a problem in EXECUTION, then you need to make a tuning exercise over your procedure.

Resources