views:

149

answers:

4

I have a oracle table with record count of 99896618.

I need to fetch small chunk of data(lets say 100 records) to show it on a web page,(In web world we call it paging). Currently I am using the following query to accomplish that however users are not satisfied with the performance.

SELECT * FROM (select rownum rnum,f.* from  findings f where rownum<90000100 ) 
                    WHERE rnum > 90000000 

Currently it is taking 1 min 22 seconds to get the results. Is there anyway to make it better. I am certainly open for any type of suggestions including modifying the table structure or like adding indexes.

(Just FYI,I am using ASP.NET as server side web technology and ADO.NET as data access layer and silverlight for client side presentation)

+1  A: 

If you are willing to modify the table I would suggest that you add a rownumber column to the table (using an insert trigger and a sequence to set it) and then you add an index to that column.

klausbyskov
There's no non-clustered or clustered indexes in Oracle - they're just called indexes.
OMG Ponies
`@OMG Ponies`: yes, but there are indexed clusters in `Oracle`! :)
Quassnoi
@OMG Ponies: A primary key is a clustered index in oracle and all none primary key indexes are non-clustered. You must be talking about the `nonclustered` *keyword* which I'm aware does not exist in oracle.
klausbyskov
`@klausbyskov`: In `Oracle` world, there are no clustered or nonclustered indexes, there are index-organized and heap-organized tables. By default, the tables are heap organized, which is what `SQL Server` calls "a table without a clustered index".
Quassnoi
@Quassnoi Ok, thank you for the clarification. I have removed the word *non-clustered* from my answer.
klausbyskov
@Quassnoi: Cluster Index :P http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:586423377841
OMG Ponies
`@OMG Ponies`: that's exactly what I was talking of :) When you create an index on a cluster, the cluster becomes an *indexed cluster*. http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_5001.htm: *Specify `INDEX` to create an indexed cluster*
Quassnoi
@Quassnoi: Ask Tom > Oracle documenation :p BTW: backticking the username means they don't show up in the users' profile comments - glad to see they implemented that.
OMG Ponies
@Quassnoi and @OMG Ponies: I was actually talking about clustered vs. nonclustered in terms of general database theoy, such as described here: http://en.wikipedia.org/wiki/Index_%28database%29 I just thought I would remove it from my answer in order to avoid that the noisy comments would remove the OP's focus from the general idea of my answer, and not necessarily because I thought that you guys were right :-P (although I do admit that your terminology was more correct for the specific dbms in question)
klausbyskov
@klausbyskov: Indexes aren't part of the ANSI SQL, lucky the vendors use similar terminology. If you delete the answer, you'll loose the vote in a recalculation. And Quassnoi is the noisy one :p
OMG Ponies
+2  A: 

Your query will need to count off the first 90M records to get the next 100, so there is hardly a room for improvement.

I don't see an ORDER BY clause in your subquery, but probably you have it. In this case, you may want to create an index on it.

And a question: do your users really click through 900K pages before complaining about performance?

Update:

If you need the latest page, you need to rewrite your ORDER BY column in descending order:

SELECT  *
FROM    (
        SELECT  rownum rnum, f.*
        FROM    findings f
        ORDER BY
                record_ordering_column DESC
        ) 
WHERE   rnum > 900
        AND rownum <= 100

and create an index on record_ordering_column

Note that I mix rownum's from the nested queries to improve performance.

See this article in my blog for more detail:

Quassnoi
I made page number easily accessible by creating a dropdown list of page numbers(just a simplified description, I have created a custom control through which they can access last 1000 pages easily).May be this is useful info, most of the time(around 95% of the time) users are interested in the last(latest) records.
funwithcoding
+4  A: 

From one of your comments:

most of the time(around 95% of the time) users are interested in the last(latest) records

In that case, why not show the records in reverse order so that 95% of the time the users are interested in page 1 rather than page 900,000?

If they really then want to see "page 900,000", that means they are interested in data from a long time ago, so allow them to filter data by e.g. date range. Just paging through 100 million rows without any filtering is never going to be performant.

Tony Andrews
A: 

Do you really need to get the whole row back? As this means that you are not using any indexes.

If you still need to get the whole row. Use the following pattern:

SELECT * FROM findings f1 WHERE f1.rowid IN
   (SELECT  rownum rnum, row_id
      FROM (
            SELECT f.rowid row_id
              FROM findings f
          ORDER BY record_ordering_column
           ) 
     WHERE rownum > 900
   )
WHERE rnum <= 100;

See AskTom

Note: the subtle extra SELECT clause as well as using the ROWID querying.

If you add an index on record_ordering_column, then the paganation will use the index to get a set of ROWIDs. Then only load the blocks that contain the rows identified by their ROWIDs.

This will be better than your current query that will be a full table scan.

PenFold