Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
Home -> Community -> Usenet -> c.d.o.misc -> Re: Problem with Order by of a date
On 2005-11-09, ChrisF <chris.freel_at_daibasel.ch> wrote:
> As everyone says, the problem is that your query takes the specified
> number or rows, and then does the SORT on those, but you need it to do
> the sort first.
> Malcolm's method above works, but the disadvantage is that if you have
> 10000 rows in the table it sorts all 10000, which is inefficient if you
> just want one returned.
>
> Another method (using your table name):
>
> SELECT a.lista_campi_tpr, date_import
> FROM CELL_PR cp
> WHERE cp.id_cella = 'PZ81U1'
> AND date_import =
> (SELECT MAX(date_import)
> FROM CELL_PR cp
> WHERE cp.id_cella = 'PZ81U1')
> AND ROWNUM < 2
>
> This passes through the table twice (once to find the MAX(), and a
> second time to find the row it wants), but it should still be faster
> than sorting the whole table unnecessarily. You still need the "ROWNUM
>< 2", in case there are two rows with identical date_import, then it
> returns the first one it finds.
This is not true, at least not in Oracle 10g.
Consider:
create table some_dates (
dt date,
txt varchar2(100)
);
begin
for i in 1 .. 100000 loop
insert into some_dates values (
sysdate - dbms_random.value(1,5000), dbms_random.string('p', 100));
set autotrace on statistics;
select *
from (
select dt, txt from some_dates
order by dt desc
)
where rownum < 2;
Statistics
0 recursive calls 0 db block gets 1635 consistent gets 0 physical reads 0 redo size 564 bytes sent via SQL*Net to client 381 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 1 rows processed
select *
from (
select dt, txt from some_dates
order by dt desc
)
where rownum < 2;
Statistics
0 recursive calls 0 db block gets 3236 consistent gets 0 physical reads 0 redo size 564 bytes sent via SQL*Net to client 381 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
select dt, txt
from some_dates sd
where dt = (
select max(dt)
from some_dates
)
and rownum < 2;
Statistics
0 recursive calls 0 db block gets 1635 consistent gets 0 physical reads 0 redo size 564 bytes sent via SQL*Net to client 381 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 1 rows processed -- -- As can be seen, the row_number() and the one with the -- inner select are both equally efficient, having -- 1635 consistent gets each. -- -- The one with the inner select to find the maximum -- value and then the outer select to find the row -- (with both selects performing a full table scan) -- is less efficient: 3236 consistent gets, almost -- the double amount. Which is not surprising because -- it scans the table twice instead of once. -- -- Yet, why is that?
-- -- Explain plan helps: explain plan for select * from ( select dt, txt from some_dates order by dt desc ) where rownum < 2; select * from table(dbms_xplan.display); ------------------------------------------------------------------------ cut | Id | Operation | Name | Rows | Bytes | Cost (%CP cut ------------------------------------------------------------------------ cut | 0 | SELECT STATEMENT | | 1 | 61 | 364 ( cut |* 1 | COUNT STOPKEY | | | | cut | 2 | VIEW | | 122K| 7282K| 364 ( cut |* 3 | SORT ORDER BY STOPKEY| | 122K| 7282K| 364 ( cut | 4 | TABLE ACCESS FULL | SOME_DATES | 122K| 7282K| 364 ( cut ------------------------------------------------------------------------ cut -- The key here is the 'SORT ORDER BY STOPKEY' explain plan for select dt, txt from some_dates sd where dt = ( select max(dt) from some_dates ) and rownum < 2; select * from table(dbms_xplan.display); ---------------------------------------------------------------------- cut | Id | Operation | Name | Rows | Bytes | Cost (%CPU cut ---------------------------------------------------------------------- cut | 0 | SELECT STATEMENT | | 1 | 61 | 728 (2 cut |* 1 | COUNT STOPKEY | | | | cut |* 2 | TABLE ACCESS FULL | SOME_DATES | 1 | 61 | 365 (2 cut | 3 | SORT AGGREGATE | | 1 | 9 | cut | 4 | TABLE ACCESS FULL| SOME_DATES | 122K| 1074K| 363 (2 cut ---------------------------------------------------------------------- cut -- In fact, here: two TABLE ACCESS FULL explain plan for select dt, txt from ( select dt, txt, row_number() over (order by dt desc) r from some_dates ) where r < 2; select * from table(dbms_xplan.display); ------------------------------------------------------------------------cut | Id | Operation | Name | Rows | Bytes |TempSpc| cut ------------------------------------------------------------------------cut | 0 | SELECT STATEMENT | | 122K| 8834K| | cut |* 1 | VIEW | | 122K| 8834K| | cut |* 2 | WINDOW SORT PUSHED RANK| | 122K| 7282K| 16M| cut | 3 | TABLE ACCESS FULL | SOME_DATES | 122K| 7282K| | cut ------------------------------------------------------------------------cut -- Only one full table scan as well. hth Rene -- Rene Nyffenegger http://www.adp-gmbh.ch/Received on Thu Nov 10 2005 - 15:18:37 CST