Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion Groups
Database Servers
DB2InformixIngresMS SQLOraclePervasive.SQLPostgreSQLProgressSybase
Desktop Databases
FileMakerFoxProMS AccessParadox
General
General DB TopicsDatabase Theory
Related Topics
Java Development.NET DevelopmentVB DevelopmentMore Topics ...

Database Forum / Oracle / Oracle Server / September 2005

Tip: Looking for answers? Try searching our database.

Avoiding a Double Cursor...

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
redrobot5050@gmail.com - 29 Sep 2005 15:54 GMT
Another question about web apps built with the PL/SQL web cartridge. We
have procedures which display data from the db to the user in a table
format. We show the first 45 results, and if the user needs more, there
are links to other "page numbers" at the bottom of the table.

To properly limit our data, we need a count of all the records that are
going to be returned by the query.

Since we use weak reference cursors, the rowcount attribute (in Oracle
9i) only tells us which row we're currently on. So we loop through the
whole cursor one time, counting up all the rows. Then we close and
re-open the cursor, and start iterating through it, displaying rows to
the user.

Is there a better way to get the total results returned? I have tried
wrapping the query in a "SELECT COUNT (*) FROM ( << query goes here >>
)" and then executing immediate, but that does not seem to work either.

does anyone have suggestions?

Thanks
stephen O'D - 29 Sep 2005 22:03 GMT
> Another question about web apps built with the PL/SQL web cartridge. We
> have procedures which display data from the db to the user in a table
[quoted text clipped - 17 lines]
>
> Thanks

The problem here is that Oracle cannot know how many rows are going to
be returned with actually getting them.

However, don't loop over all the rows once to get the row count, and
then again to get the rows you want - that will be very slow.

Create a new query which is

select count(*)
from <the rest of you query>

ie, the exact same where clause as you actual select.  The count(*)
will be much faster than actually retriving the data.

Then open the original cursor to get the rows you want.  The best way
to limit the rows here is to use rownum - in this was you can bring
back a 'window' of results from the database:-

 1  select *
 2  from
 3  (
 4    select * from
 5    (
 6      select rownum rnum, ename
 7      from emp
 8      order by ename
 9    ) where rnum <= 5
10* ) where rnum >= 2

This query will return rows 2 to 5 inclusive.

 1  select *
 2  from
 3  (
 4    select * from
 5    (
 6      < ** your entire query goes here including order by ** >
 9    ) where rnum <= max_row
10* ) where rnum >= min_row

Obviously this means you need to have two ref cursors, but it will
probably be faster.

One other option you could try is:

 1  select *
 2  from
 3  (
 4    select * from
 5    (
 6      select rownum rnum, ename, count(*) over ()
 7      from emp
 8      order by ename
 9    ) where rnum <= 5
10* ) where rnum >= 2

In this case the total count will be on each row returned, and you
could grand it on the first pass of processing the results.
I am not sure if this would be more efficient - but I guess I can test
it out while I am here:

SQL> create table big_table (id integer, value varchar2(255))
 2  ;

Table created.

SQL> insert into big_table select object_id, object_name from
all_objects;

30314 rows created

SQL> select count(*) from big_table;

 COUNT(*)
----------
    30314

Statistics
----------------------------------------------------------
         1  recursive calls
         1  db block gets
       188  consistent gets
         0  physical reads
       120  redo size
       381  bytes sent via SQL*Net to client
       503  bytes received via SQL*Net from client
         2  SQL*Net roundtrips to/from client
         0  sorts (memory)
         0  sorts (disk)
         1  rows processed

 1  select *
 2  from
 3  (
 4    select *
 5    from
 6    (
 7      select rownum rnum, id, value
 8      from big_table
 9      order by value
10    ) where rnum <= 45
11* ) where rnum >= 1

45 rows selected.

Statistics
----------------------------------------------------------
         0  recursive calls
         4  db block gets
       184  consistent gets
       156  physical reads
         0  redo size
      2465  bytes sent via SQL*Net to client
       525  bytes received via SQL*Net from client
         4  SQL*Net roundtrips to/from client
         0  sorts (memory)
         1  sorts (disk)
        45  rows processed

So thats 184 + 184 = 268 consistent gets for this case.

 1  select *
 2  from
 3  (
 4    select *
 5    from
 6    (
 7      select rownum rnum, id, value, count(*) over ()
 8      from big_table
 9      order by value
10    ) where rnum <= 45
11* ) where rnum >= 1

Statistics
----------------------------------------------------------
         0  recursive calls
         6  db block gets
       184  consistent gets
       471  physical reads
         0  redo size
      2619  bytes sent via SQL*Net to client
       525  bytes received via SQL*Net from client
         4  SQL*Net roundtrips to/from client
         0  sorts (memory)
         1  sorts (disk)
        45  rows processed

So, only 184 consistent gets in total - but there are many more
physical reads here for some reason.  I am afraid I am not sure why -
could it to be with the sorting?

I guess you could try both methods and see which performs better for
you data and where clause etc.

Stephen.
GWood - 29 Sep 2005 22:40 GMT
I had always thought that Oracle could/would not guarantee any consistency
using rownum(), i.e. using it repreatedly as a limit in a where clause would
not always return the expected set of rows?

Since this idea goes back to the DB each time for a new page of data, can
you be sure rownum() will get the appropriate set of rows?

Cheers
Gary

> > Another question about web apps built with the PL/SQL web cartridge. We
> > have procedures which display data from the db to the user in a table
[quoted text clipped - 173 lines]
>
> Stephen.
stephen O'D - 30 Sep 2005 13:17 GMT
Gary,

So long as you do the orderby in the inner query and then filter the
rows in the outer querys everything works fine.

If there are new rows added between accessing different pages of data
you will receive a different set of results - but that is probably the
right thing todo anyway in this case.
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2010 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.