Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
У вас же запросы с max и dense_rank дают разный результат!
минимальный ID операциии тут же приводите пример из моего кода
order by c.oper_id desc)который говорит о том, что отсортировано по убыванию, и dense_rank поставит единицу там где будет максимальное значение.
drop table habr_test_table purge;
/*создаем табличку*/
create table habr_test_table
(
oper_id
,client_id
,input_date
,amount
,constraint habr_test_table_pk primary key (oper_id)
)
as
select
rownum
,trunc(dbms_random.value (1, 11))
,to_date(trunc(dbms_random.value(to_char(date '2013-01-01','j'),to_char(date '2013-12-31','j'))),'j')
,trunc (dbms_random.value (1, 100000))
from dual
connect by level<=50000;
-- Добавим дубли
insert into habr_test_table(oper_id,client_id,input_date,amount)
select rownum+50000,client_id,input_date,amount from habr_test_table;
commit;
call dbms_stats.gather_table_stats(user,'HABR_TEST_TABLE');
call dbms_stats.gather_table_stats(user,'HABR_TEST_TABLE');
set echo on serverout off feed on timing on;
spool tests_habr.sql
-- ! on test db only !
alter system flush shared_pool;
alter session set "_optimizer_use_feedback"=false;
alter session set statistics_level=all;
-- 2 max:
select/*+ findme 1 */ * from
(
select c.*
, max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
from
(
select t.*
, max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
from habr_test_table t
) c
where c.m_a = c.amount
) where m_o = oper_id;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
-- 2 dense_rank:
select/*+ findme 2 */ * from
(
select c.*
, dense_rank() over (partition by c.client_id order by c.oper_id desc) as m_o/*max_operation*/
from
(
select t.*
, dense_rank() over (partition by t.client_id order by t.amount desc) as m_a/*max_amount*/
from habr_test_table t
) c
where c.m_a = 1
) where m_o = 1;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
-- 2 max + order by:
select/*+ findme 3 */ * from
(
select c.*
, max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
from
(
select t.*
, max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
from habr_test_table t
order by t.client_id
) c
where c.m_a = c.amount
) where m_o = oper_id;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
-- 1 row_number:
select/*+ findme 4 */ * from
(
select t.*
, row_number() over (partition by t.client_id order by t.amount desc, t.oper_id desc) as rn
from habr_test_table t
) where rn = 1;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
select
substr(sql_text,1,18) as text
,sql_id
,elapsed_time
,s.cpu_time
,s.user_io_wait_time
,s.BUFFER_GETS
,s.executions
from v$sql s
where s.sql_text like 'select/*+ findme %'
order by 1;
spool off;
set echo off timing off;
TEXT SQL_ID ELAPSED_TIME CPU_TIME USER_IO_WAIT_TIME BUFFER_GETS EXECUTIONS
-------------------- ------------- ------------ ---------- ----------------- ----------- ----------
select/*+ findme 1 6swypwnq6kxvy 1052892 920000 120803 454 1
select/*+ findme 2 0dgjzaawppasx 883205 860000 10838 394 1
select/*+ findme 3 am5gh1pxv4d43 940052 840000 103318 394 1
select/*+ findme 4 cyr7z0c7zq24p 764480 750000 11194 394 1
-- 1 row_number:
select/*+ findme 4 */ * from
(
select t.*
, row_number() over (partition by t.client_id order by t.amount desc, t.oper_id desc) as rn
from habr_test_table t
) where rn = 1;
SQL> -- 2 max:
SQL> select/*+ findme 1 */ * from
2 (
3 select c.*
4 , max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
5 from
6 (
7 select t.*
8 , max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
9 from habr_test_table t
10 ) c
11 where c.m_a = c.amount
12 ) where m_o = oper_id;
Plan hash value: 673711813
----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
----------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:01.02 | 392 | 1151 | 775 | | | | |
|* 1 | VIEW | | 1 | 99720 | 10 |00:00:01.02 | 392 | 1151 | 775 | | | | |
| 2 | WINDOW BUFFER | | 1 | 99720 | 20 |00:00:01.02 | 392 | 1151 | 775 | 2048 | 2048 | 2048 (0)| |
|* 3 | VIEW | | 1 | 99720 | 20 |00:00:01.02 | 392 | 1151 | 775 | | | | |
| 4 | WINDOW SORT | | 1 | 99720 | 100K|00:00:00.97 | 392 | 1151 | 775 | 3519K| 815K| 1179K (1)| 5120 |
| 5 | TABLE ACCESS FULL| HABR_TEST_TABLE | 1 | 99720 | 100K|00:00:00.08 | 381 | 376 | 0 | | | | |
----------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("M_O"="OPER_ID")
3 - filter("C"."M_A"="C"."AMOUNT")
SQL> -- 2 dense_rank:
SQL> select/*+ findme 2 */ * from
2 (
3 select c.*
4 , dense_rank() over (partition by c.client_id order by c.oper_id desc) as m_o/*max_operation*/
5 from
6 (
7 select t.*
8 , dense_rank() over (partition by t.client_id order by t.amount desc) as m_a/*max_amount*/
9 from habr_test_table t
10 ) c
11 where c.m_a = 1
12 ) where m_o = 1;
Plan hash value: 331359864
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.87 | 394 | 387 | 11 | | | | |
|* 1 | VIEW | | 1 | 99720 | 10 |00:00:00.87 | 394 | 387 | 11 | | | | |
|* 2 | WINDOW SORT PUSHED RANK | | 1 | 99720 | 20 |00:00:00.87 | 394 | 387 | 11 | 2048 | 2048 | 2048 (0)| |
|* 3 | VIEW | | 1 | 99720 | 20 |00:00:00.87 | 394 | 387 | 11 | | | | |
|* 4 | WINDOW SORT PUSHED RANK| | 1 | 99720 | 30 |00:00:00.87 | 394 | 387 | 11 | 92160 | 92160 | 1123K (2)| 1024 |
| 5 | TABLE ACCESS FULL | HABR_TEST_TABLE | 1 | 99720 | 100K|00:00:00.09 | 381 | 376 | 0 | | | | |
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("M_O"=1)
2 - filter(DENSE_RANK() OVER ( PARTITION BY "C"."CLIENT_ID" ORDER BY INTERNAL_FUNCTION("C"."OPER_ID") DESC )<=1)
3 - filter("C"."M_A"=1)
4 - filter(DENSE_RANK() OVER ( PARTITION BY "T"."CLIENT_ID" ORDER BY INTERNAL_FUNCTION("T"."AMOUNT") DESC )<=1)
SQL> -- 2 max + order by:
SQL> select/*+ findme 3 */ * from
2 (
3 select c.*
4 , max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
5 from
6 (
7 select t.*
8 , max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
9 from habr_test_table t
10 order by t.client_id
11 ) c
12 where c.m_a = c.amount
13 ) where m_o = oper_id;
Plan hash value: 673711813
----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
----------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.93 | 394 | 1284 | 908 | | | | |
|* 1 | VIEW | | 1 | 99720 | 10 |00:00:00.93 | 394 | 1284 | 908 | | | | |
| 2 | WINDOW BUFFER | | 1 | 99720 | 20 |00:00:00.93 | 394 | 1284 | 908 | 2048 | 2048 | 2048 (0)| |
|* 3 | VIEW | | 1 | 99720 | 20 |00:00:00.93 | 394 | 1284 | 908 | | | | |
| 4 | WINDOW SORT | | 1 | 99720 | 100K|00:00:00.88 | 394 | 1284 | 908 | 3519K| 815K| 1123K (2)| 4096 |
| 5 | TABLE ACCESS FULL| HABR_TEST_TABLE | 1 | 99720 | 100K|00:00:00.07 | 381 | 376 | 0 | | | | |
----------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("M_O"="OPER_ID")
3 - filter("C"."M_A"="C"."AMOUNT")
SQL> -- 1 row_number:
SQL> select/*+ findme 4 */ * from
2 (
3 select t.*
4 , row_number() over (partition by t.client_id order by t.amount desc, t.oper_id desc) as rn
5 from habr_test_table t
6 ) where rn = 1;
Plan hash value: 19323224
-------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
-------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.76 | 394 | 387 | 11 | | | | |
|* 1 | VIEW | | 1 | 99720 | 10 |00:00:00.76 | 394 | 387 | 11 | | | | |
|* 2 | WINDOW SORT PUSHED RANK| | 1 | 99720 | 20 |00:00:00.76 | 394 | 387 | 11 | 92160 | 92160 | 1123K (2)| 1024 |
| 3 | TABLE ACCESS FULL | HABR_TEST_TABLE | 1 | 99720 | 100K|00:00:00.07 | 381 | 376 | 0 | | | | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN"=1)
2 - filter(ROW_NUMBER() OVER ( PARTITION BY "T"."CLIENT_ID" ORDER BY INTERNAL_FUNCTION("T"."AMOUNT") DESC ,INTERNAL_FUNCTION("T"."OPER_ID") DESC
)<=1)
… И четко помня, что «qualify» в оракле нет, я написал на бумажке что то на подобии:
select t.* from some_table t
where amount = max(t.oper_id) over (partition by t.client_id)
«Dense_rank()» vs «Max()» или расследование с неожиданным концом