.
8i , .
, , ROW_NUMBER , Quassnoi.
, 9, Oracle .
FK_USER FIRST LAST.
FIRST: http://download.oracle.com/docs/cd/B10501_01/server.920/a96540/functions45a.htm#SQLRF00641
LAST: http://download.oracle.com/docs/cd/B10501_01/server.920/a96540/functions57a.htm#83735
:
SQL> create table thistory (id,fk_user,state,timestamp)
2 as
3 select 1, 'Me', 'D', sysdate from dual union all
4 select 2, 'Me', 'C', sysdate-1 from dual union all
5 select 3, 'Me', 'B', sysdate-2 from dual union all
6 select 4, 'Me', 'A', sysdate-3 from dual union all
7 select 5, 'You', 'B', sysdate-11 from dual union all
8 select 6, 'You', 'A', sysdate-12 from dual
9 /
Table created.
SQL> exec dbms_stats.gather_table_stats(user,'thistory')
PL/SQL procedure successfully completed.
SQL> alter session set statistics_level = all
2 /
Session altered.
SQL> set serveroutput off
pre-8i :
SQL> select *
2 from thistory
3 where timestamp =
4 ( select max(timestamp)
5 from thistory latest
6 where fk_user = thistory.fk_user
7 )
8 /
ID FK_USER S TIMESTAMP
---------- ------- - -------------------
1 Me D 19-05-2011 11:20:48
5 You B 08-05-2011 11:20:48
2 rows selected.
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
2 /
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------
SQL_ID 306v8p42zdz34, child number 0
-------------------------------------
select * from thistory where timestamp = ( select max(timestamp) from thistory latest
where fk_user = thistory.fk_user )
Plan hash value: 2894184026
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------
|* 1 | HASH JOIN | | 1 | 2 | 2 |00:00:00.01 | 7 | 1155K| 1155K| 478K (0)|
| 2 | VIEW | VW_SQ_1 | 1 | 2 | 2 |00:00:00.01 | 3 | | | |
| 3 | HASH GROUP BY | | 1 | 2 | 2 |00:00:00.01 | 3 | | | |
| 4 | TABLE ACCESS FULL| THISTORY | 1 | 6 | 6 |00:00:00.01 | 3 | | | |
| 5 | TABLE ACCESS FULL | THISTORY | 1 | 6 | 6 |00:00:00.01 | 4 | | | |
----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("TIMESTAMP"="VW_COL_1" AND "FK_USER"="THISTORY"."FK_USER")
22 rows selected.
:
SQL> select *
2 from ( select h.*
3 , row_number() over (partition by h.fk_user order by timestamp desc) as rn
4 from thistory h
5 )
6 where rn = 1
7 /
ID FK_USER S TIMESTAMP RN
---------- ------- - ------------------- ----------
1 Me D 19-05-2011 11:20:48 1
5 You B 08-05-2011 11:20:48 1
2 rows selected.
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
2 /
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------
SQL_ID b7zscht24wa2s, child number 0
-------------------------------------
select * from ( select h.* , row_number() over (partition by h.fk_user order by timestamp desc)
as rn from thistory h ) where rn = 1
Plan hash value: 2357375523
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
|* 1 | VIEW | | 1 | 6 | 2 |00:00:00.01 | 3 | | | |
|* 2 | WINDOW SORT PUSHED RANK| | 1 | 6 | 6 |00:00:00.01 | 3 | 9216 | 9216 | 8192 (0)|
| 3 | TABLE ACCESS FULL | THISTORY | 1 | 6 | 6 |00:00:00.01 | 3 | | | |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN"=1)
2 - filter(ROW_NUMBER() OVER ( PARTITION BY "H"."FK_USER" ORDER BY INTERNAL_FUNCTION("TIMESTAMP") DESC )<=1)
21 rows selected.
And finally, the most efficient option using aggregate functions:
SQL> select max(id) keep (dense_rank last order by timestamp) id
2 , fk_user
3 , max(state) keep (dense_rank last order by timestamp) state
4 , max(timestamp)
5 from thistory
6 group by fk_user
7 /
ID FK_USER S MAX(TIMESTAMP)
---------- ------- - -------------------
1 Me D 19-05-2011 11:20:48
5 You B 08-05-2011 11:20:48
2 rows selected.
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
2 /
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------
SQL_ID 9gcbnuf776q27, child number 0
-------------------------------------
select max(id) keep (dense_rank last order by timestamp) id , fk_user , max(state) keep
(dense_rank last order by timestamp) state , max(timestamp) from thistory group by fk_user
Plan hash value: 76026975
--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------
| 1 | SORT GROUP BY | | 1 | 2 | 2 |00:00:00.01 | 3 | 9216 | 9216 | 8192 (0)|
| 2 | TABLE ACCESS FULL| THISTORY | 1 | 6 | 6 |00:00:00.01 | 3 | | | |
--------------------------------------------------------------------------------------------------------------------
14 rows selected.
If you closely follow the plans, you will see that the last of them is the most effective. And it does not require an inline view.
Hope this helps.
Regards,
Rob.