Está en la página 1de 11

eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

Por:Serglo Rufuel Clunuzzu en:vle z de Lne, zoo, o,:o LS1 (6o LecLurus)
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
LL slgulenLe urLiculo es unu Lruducclon uroxlmudu de un urLiculo ubllcudo en el numero de SeLlembrejOcLubre
del zoo6 de lu revlsLu Orucle.
eeEEEEeeEeeEEeeeeeeeeEeeeeeeeEEeeeeEEE
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee LL slgulenLe urLlculo es unu Lruducclon uroxlmudu de un urLlculo ubllcudo en el numero
de SeLlembrejOcLubre del zoo6 de lu revlsLu Orucle.
Eeeeeeeeeeeeeeeeeeeeee
ROWNUM es unu columnu muglcu que exlsLe en Orucle que generu clerLu confuslon enLre los desurrolludores. Sln emburgo, cuundo
uno urende que es y como funclonu, uede ser exLremudumenLe uLll. Se usu rlnclulmenLe uru dos cosus: . Puru obLener los
rlmeros N reglsLros. LsLo es slmllur u uLlllzur lu cluusulu LlMl1, dlsonlble en oLrus buse de duLos. z. Puru uglnur querles, Lilco en
umblenLes sLuLeless como lu Web. veremos cudu unu de esLus uLllldudes luego de exllcur como funclonu ROWNUM.
EeeeeMeeeeeeeeeeeeee
ROWNUM es unu seudocolumnu (no unu columnu reul) que esLu dlsonlble en los resulLudos de los querles. ROWNUM Lendru
uslgnudos los numero ,z,,...,N donde N es el numero de fllus en el resulLudo. Un vulor ROWNUM no es uslgnudo ermunenLemenLe u
unu fllu (esLe es un error de conceLo comun). Unu fllu en lu Lublu NO Llene nlngun numero uslgnudo, no se uede edlr que Le devuelvu
lu fllu de unu Lublu, no exlsLe Lul cosu.
OLru cosu que suele confundlr mucho es suber cuundo se uslgnu el ROWNUM. Ll vulor de ROWNUM es uslgnudo u unu fllu luego de que
uso lu fuse de redlcudo del query ero unLes que el query use or ulgun ordenumlenLo o ugreguclon. Ademus, un vulor ROWNUM es
lncremenLudo solumenLe luego de ser usglnudo, lo que exllcu or que el slgulenLe query no devuelve nlngunu fllu:
~np~
select * from t where ROWNUM > 1
~/np~
Lebldo u que ROWNUM > no es verdudero uru lu rlmer columnu, ROWNUM nuncu uvunzu u z. Por ello, nlngun vulor de ROWNUM
es muyor que . Consldere un query con lu slgulenLe esLrucLuru:
~np~
select ...,ROWNUM from t where group by having order by ;
~/np~
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 1f11
Lo unLerlor es rocesudo de lu slgulenLe muneru:
. Lu cluusulu lROMjWHLRL vu rlmero.
z. ROWNUM es uslgnudo e lncremenLudo uru cudu fllu obLenldu en el lROMjWHLRL.
. Ll SLLLC1 es ullcudo.
. Ll CROUP 8Y es ullcudo.
. Ll HAvlNC es ullcudo.
6. Ll ORLLR 8Y es ullcudo.
Ls or eso que el query exresudo de lu slgulenLe muneru es cusl un error:
~np~
select *
from emp
where ROWNUM <= 5
order by sal desc;
~/np~
Lu lnLenclon eru rlnclulmenLe obLener lus clnco ersonus me|or ugus en unu Lo-N query. Lo que el query vu u reLornur
verduderumenLe son los rlmeros clnco reglsLros uleuLorlos ( Los rlmeros clnco que encuenLre ) ordenudos or sulurlo. Ll
seudocodlgo rocedlmenLul uru esLu query seriu el slgulenLe:
~np~
ROWNUM = 1
for x in
( select * from emp )
loop
exit when NOT(ROWNUM <= 5)
OUTPUT record to temp
ROWNUM = ROWNUM+1
end loop
SORT TEMP
~/np~
LsLe codlgo obLlene los clnco rlmeros reglsLros y los ordenu. Un query con WHLRL ROWNUM = o WHLRL ROWNUM > no Llene
senLldo. LsLo es orque un vulor ROWNUM se uslgnu u unu fllu durunLe lu evuluuclon del redlcudo y se lncremenLe solo desues de
que unu fllu es obLenldu or lu cluusulu WHLRL. Aqui Lenemos lu verslon correcLu del query:
~np~
select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;
~/np~
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 2f11
LsLu verslon ordenuru lu Lublu LMP or sulurlo de muneru descendenLe y reLornuru los clnco rlmeros reglsLros que encuenLre. Lu buse
de duLos es lo suflclenLemenLe lnLellgenLe como uru no ordenur reulmenLe el con|unLo enLero de resulLudos, ero conceLuulmenLe es
lo que sucede.
MeeeeeeeeeeeeeeeeeeMMeeMeeeeeeeeeeeeeeeee
Un Lo-N query, generulmenLe se reullzu ensundo en ulgunu consulLu comle|u, ordenundolu y osLerlormenLe recuerundo lus
rlmerus N fllus (Lo N). ROWNUM Llene unu oLlmlzuclon Lo-N que fuclllLu esLe Llo de consulLu. Puede usur ROWNUM uru evlLur
un ordenumlenLo muslvo de un con|unLo muy grunde de reglsLros.Prlmero se mosLruru esLu ldeu conceLuulmenLe y desues u Lruves
de un e|emlo. Suongu que Llene unu consulLu de esLu formu:
~np~
select ...
from ...
where ...
order by columns;
~/np~
Asumu que esLe query reLornu muchos duLos: mlles, clenLos de mlles, o mus fllus. Sln emburgo, usLed esLu lnLeresudo solumenLe en los
Lo-N, or e|emlo, los o o oo rlmeros. Huy dos formus de hucerlo:
. Hucer que lu ullcuclon cllenLe corru dlcho query y exLrulgu solo lus rlmerus N fllus.
z. Usur el query como unu vlsLu lnllne, y usur ROWNUM uru llmlLur los resulLudos, como en SLLLC1 * lROM (su_consulLu_uqul)
WHLRL ROWNUM <= N.
Lu segundu uroxlmuclon es or mucho suerlor u lu rlmeru debldo u dos ruzones. Lu rlmeru es que requlere menos Lrubu|o de urLe
del cllenLe, orque lu buse de duLos se ocuun de llmlLur el resulLseL. Lu mus lmorLunLe es el rocesumlenLo eseclul que uede hucer
lu buse de duLos uru durle solo lus N rlmerus fllus. Al usur el Lo-N query, se du u lu buse de duLos unu lnformuclon exLru. UsLed le hu
dlcho: LsLoy lnLeresudo solumenLe en obLener N fllus, no me lmorLu el resLo. Ahoru, eso no suenu nudu del oLro mundo husLu que se
lensu en el Lrubu|o que lmllcu uru el servldor hucer el Lrubu|o de ordenumlenLo. Lemos un recorrldo u lus dos uroxlmuclones con un
query de muesLru:
~np~
select *
from t
order by unindexed_column;
~/np~
Ahoru usumu que 1 es unu Lublu grunde, con mus de un mlllon de reglsLros, y cudu reglsLro es gordo, dlgumos, oo o mus byLes.
1umblen usumu que UNlNLLXLL_COLUMN es, como su nombre lo lmllcu, unu columnu que no esLu lndexudu y usumu que usLed
esLu lnLeresudo en obLener solumenLe lus o rlmerus fllus. Lu buse de duLos Orucle reullzuriu lo slgulenLe:
. Un full scun sobre lu Lublu 1. z. Ordenur 1 or UNlNLLXLL_COLUMN. LsLo es un ordenumlenLo comleLo. . PoslblemenLe
sobreuse el ureu de memorlu y neceslLe hucer swulngs de duLos LemorulmenLe u dlsco. . Huce un merge con los duLos
LemorulmenLe bu|udos u dlsco uru obLener los o rlmeros reglsLros cuundo seun sollclLudos. . Llmlu los duLos Lemorules cuundo
se de|un de uLlllzur.
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 3f11
se de|un de uLlllzur.
Ahoru, esLo es mucho Lrubu|o de LjS. Lu buse de duLos Orucle muy robublemenLe hu coludo Lodu lu Lublu en 1LMP y lu hu borrudo,
solo uru obLener lus o rlmerus fllus.
PosLerlormenLe, veumos conceLuulmenLe lo que Orucle uede hucer con un Lo-N query:
~np~
select *
from
(select *
from t
order by unindexed_column)
where ROWNUM < :N;
~/np~
Ln esLe cuso, Orucle huru los slgulenLes usos: . Un burrldo comleLo sobre 1, como en el unLerlor cuso (esLe uso no se uede omlLlr).
z. Ln un urreglo de :N elemenLos (se resume que esLun curgudos en memorlu esLu vez), ordene solo :N fllus. Lus rlmerus N fllus
oblurun esLe urreglo de fllus de muneru ordenudu. Cuundo lus rlmerus N fllus son Lruidus, se comururun con lu ulLlmu fllu en el
urreglo. Sl llegu husLu lu oslclon N en el urreglo, esLu se descurLu. Le oLru formu, se udlclonu ul urreglo y se ordenu y unu de lus fllus
que esLubu en el urreglo se descurLu. Ll ureu ordenudu ulmucenu N fllus muxlmo, usi, en vez de ordenur un mlllon, se ordenun N fllus.
LsLe uurenLemenLe lnslgnlflcunLe deLulle de usur el conceLo de urreglo y ordenur solo N fllus uede llevur u grundes gununclus en
erformunce y uso de recursos. Requlere muchu menos RAM ordenur o fllus que lo que Lomu ordenur un mlllon de fllus ( sln menclonur
el uso de esuclo en 1LMP ).
Usundo lu slgulenLe Lublu 1, uede ver que uunque umbus uroxlmuclones obLlenen los mlsmos resulLudos, usun cunLldudes
rudlculmenLe dlferenLes de recursos:
~np~
create table t
as
select dbms_random.value(1,1000000)
id, rpad('*',40,'*' ) data from dual
connect by level <= 100000;
begin
dbms_stats.gather_table_stats
( user, 'T');
end;
/
~/np~
Ahoru, hublllLundo Lruclng u Lruves de:
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. +f11
~np~
exec
dbms_monitor.session_trace_enable
(waits=>true);
~/np~
L|ecuLe su Lo-N query con ROWNUM:
~np~
select *
from
(select *
from t
order by id)
where rownum <= 10;
~/np~
Y flnulmenLe e|ecuLe unu consulLu do-lL-yourself que exLrulgu solo los o rlmeros reglsLros:
~np~
declare
cursor c is
select *
from t
order by id;
l_rec c%rowtype;
begin
open c;
for i in 1 .. 10
loop
fetch c into l_rec;
exit when c%notfound;
end loop;
close c;
end;
/
~/np~
Lesues de e|ecuLur esLu consulLu, uede usur 1KPROl uru formuLeur el urchlve de Lruce resulLunLe y verlflcur lo que sucedlo.
Prlmero, exumlne el Lo-N query, como se muesLru en el LlsLudo de codlgo .
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 5f11
~np~
Listado de cdigo 1: Top-N query usando ROWNUM
select *
from
(select *
from t
order by id)
where rownum <= 10
~/np~
~np~
call count cpu elapsed disk query current rows
-------- -------- ------- ------- ------- -------- -------- ------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.04 0.04 0 949 0 10
-------- -------- ------- ------- ------- -------- -------- ------
total 4 0.04 0.04 0 949 0 10
Rows Row Source Operation
----------------- ---------------------------------------------------
10 COUNT STOPKEY (cr=949 pr=0 pw=0 time=46997 us)
10 VIEW (cr=949 pr=0 pw=0 time=46979 us)
10 SORT ORDER BY STOPKEY (cr=949 pr=0 pw=0 time=46961 us)
100000 TABLE ACCESS FULL T (cr=949 pr=0 pw=0 time=400066 us)
~/np~
Ll query leyo Lodu lu Lublu ( orque debiu hucerlo ), ero usundo el uso SOR1 ORLLR 8Y S1OPKLY, udo llmlLur el uso de esuclo
Lemorul u solumenLe o fllus. NoLe que lu lineu flnul del resulLudo en Row Source OeruLlon muesLru que lu consulLu hlzo gg ljOs
loglcos, en LoLul (cr=gg), no hlzo lecLurus o escrlLurus fislcus (r=o und w=o), y Lomo ooo66 mllloneslmus de segundo (o.o
segundos). Comure eso conLru lu ulLernuLlvu do-lL-yourself mosLrudu en el LlsLudo de Codlgo z.
~np~
Listado de Cdigo 2: Consulta Do-it-yourself con ROWNUM
SELECT * FROM T ORDER BY ID
~/np~
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 6f11
~np~
call count cpu elapsed disk query current rows
-------- -------- ------- ------- ------- -------- -------- ------
Parse 1 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 10 0.35 0.40 155 949 6 10
-------- -------- ------- ------- ------- -------- -------- ------
total 13 0.36 0.40 155 949 6 10
Rows Row Source Operation
----------------- ---------------------------------------------------
10 SORT ORDER BY (cr=949 pr=155 pw=891 time=401610 us)
100000 TABLE ACCESS FULL T (cr=949 pr=0 pw=0 time=400060 us)
~/np~
Los Llemos Lrunscurrldos lncluyen eserur or los slgulenLes evenLos:
~np~
Event waited on Times
------------------------------ ------------
direct path write temp 33
direct path read temp 5
~/np~
Como odemos ver, esLe resulLudo es muy dlferenLe. Los Llemos de CPU son slgnlflcuLlvumenLe muyores, y lus lineus resulLunLes del
Row Source OeruLlon dun unu muesLru de ello. Acu se hu reullzudo un ordenumlenLo en dlsco, el cuul se uede ver con el urumeLro
w=8g (hyslcul wrlLes). Su consulLu reullzo ulgunus lecLurus y escrlLurus dlrecLus el ordenumlenLo de los oo,ooo reglsLros (en vez
de hucer los o que flnulmenLe son los que nos lnLeresun) se reullzo en dlsco udlclonundo un uso conslderuble u recursos de e|ecuclon
de su consulLu.
MeeeeeeeMeeeeeeeeeeeeeeeeeee
OLro uso de ROWNUM es lu uglnuclon. Ln esLe cuso, se usu ROWNUM uru obLener N fllus u Lruves de M en un resulL seL. Lu
esLrucLuru generul es lu slgulenLe:
~np~
select *
from ( select /*+ FIRST_ROWS(n) */
a.*, ROWNUM rnum
from ( your_query_goes_here,
with order by ) a
where ROWNUM <=
:MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
~/np~
donde:
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 7f11
llRS1_ROWS(N) le dlce ul oLlmlzudor, Che, esLoy lnLeresudo en obLener lus rlmerus fllus, y obLendre N de ellus Lun ruldo
como seu oslble.
:MAX_ROW_1O_lL1CH se colocu uru lndlcur lu ulLlmu fllu del resulL seL u Lruer sl usLed queriu Lruer o u 6o fllus del resulL
seL, debe onerlo en 6o.
:MlN_ROW_1O_lL1CH se colocu uru lndlcur lu rlmeru fllu del resulL seL u Lruer, usi, uru obLener lus fllus o u 6o, debe
onerlo en o.
Ll conceLo deLrus de esLe escenurlo es que un usuurlo con un browser hu hecho unu busquedu y esLu eserundo or los resulLudos. Ls
lmeruLlvo reLornur lu rlmeru uglnu resulLunLe ( y lu segundu, y usi suceslvumenLe ) Lun ruldo como seu oslble. Sl se fl|u mus
deLenldumenLe en lu consulLu, noLuru que lncororu un Lo-N query (obLlene lus rlmerus :MAX_ROW_1O_lL1CH fllus de su consulLu
) y en consecuenclu se beneflclu de lu oLlmlzuclon Lo-N. Yendo mus ullu, reLornu ul cllenLe, solo los resulLudos eseciflcos de lnLeres
remueve cuulquler fllu unLerlor que no seu de lnLeres. Un deLulle lmorLunLe sobre el uso de consulLus uglnudus es que lu cluusulu
ORLLR 8Y debe ordenur or ulgun elemenLo unlco. Sl lo que esLu ordenundo no es unlco, debe udlclonur ulgo ul flnul del ORLLR 8Y
uru hucerlo usi. Sl ordenu oo reglsLros oo or lu columnu SALARY, or e|emlo, y Lodos ellos Llenen el mlsmo vulor de SALARY,
enLonces, edlr lus fllus de lu zo u z reulmenLe no Llene nlngun senLldo. Puru ver esLo, use unu equenu Lublu con muchos vulores de lL
dullcudos:
~np~
SQL> create table t
2 as
3 select mod(level,5) id, trunc(dbms_random.value(1,100)) data
4 from dual
5 connect by level <= 10000;
Table created.
~/np~
Lesues, consulLe fllus de lu 8 u lu o y desues de ordenur or lu columnu lL:
~np~
SQL> select *
2 from
3 (select a.*, rownum rnum
4 from
5 (select id, data
6 from t
7 order by id) a
8 where rownum <= 150
9 )
10 where rnum >= 148;
~/np~
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 8f11
~np~
ID DATA RNUM
------- ---------- -----------
0 38 148
0 64 149
0 53 150
~/np~
~np~
SQL>
SQL> select *
2 from
3 (select a.*, rownum rnum
4 from
5 (select id, data
6 from t
7 order by id) a
8 where rownum <= 151
9 )
10 where rnum >= 148;
~/np~
~np~
ID DATA RNUM
------- ---------- -----------
0 59 148
0 38 149
0 64 150
0 53 151
~/np~
NoLe que en esLe cuso, que unu vez uru lu fllu 8, el resulLudo reLorno LA1A=8, y que lu roxlmu vez, el resulLudo reLorno LA1A=g.
Ambus consulLus esLun reLornundo exucLumenLe lu resuesLu correcLu, dudo que hu edldo: Ordene los duLos or lL, lunce lus rlmerus
, fllus, y reLorne lus slgulenLes u fllus. Ambos lo hucen, ero como el lL Llene LunLos vulores dullcudos, lu consulLu no uede
hucerlo deLermlnisLlcumenLe el mlsmo ordenumlenLo no se useguru de e|ecuclon en e|ecuclon uru lu consulLu. Con el rooslLo de
correglr esLo, neceslLu udlclonur ulgo unlco ul ORLLR 8Y. Ln esLe cuso, use ROWlL:
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 9f11
~np~
SQL> select *
2 from
3 (select a.*, rownum rnum
4 from
5 (select id, data
6 from t
7 order by id, rowid) a
8 where rownum <= 150
9 )
10 where rnum >= 148;
~/np~
~np~
ID DATA RNUM
------- ---------- -----------
0 45 148
0 99 149
0 41 150
~/np~
~np~
SQL>
SQL> select *
2 from
3 (select a.*, rownum rnum
4 from
5 (select id, data
6 from t
7 order by id, rowid) a
8 where rownum <= 151
9 )
10 where rnum >= 148;
~/np~
~np~
ID DATA RNUM
------- ---------- -----------
0 45 148
0 99 149
0 41 150
0 45 151
~/np~
Ahoru el query es deLermlnlsLlco. ROWlL es unlco denLro de lu Lublu, or lo que sl se usu ORLLR 8Y lL y luego denLro de lL se usu
ORLLR 8Y ROWlL, lus fllus Lendrun un orden deLermlnlsLlco y el query de uglnuclon devolveru deLermlnlsLlcumenLe lus fllus como se
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 10f11
ORLLR 8Y ROWlL, lus fllus Lendrun un orden deLermlnlsLlco y el query de uglnuclon devolveru deLermlnlsLlcumenLe lus fllus como se
eseru.
EeeEEeEEeeEEeEeMeEeeeeeee
Con lo unLerlor, odemos deduclr lo slgulenLe de ROWNUM:
Como ROWNUM es uslgnudo, uru que uedun escrlblrse querles llbre de errores.
Como ufecLu el rocesumlenLo de un query, uru que uedun uglnur los resulLudos en lus ullcuclones.
Como uede reduclr el Llemo de e|ecuclon de un query, uru que los querles Lo-N no consumun demusludo recursos y uedun
e|ecuLur mucho mus ruldo.
2+f05f2011 : Utilizando ROWNUN en motores Oracle
epidataconsulting.comf.ftiki-print_arti. 11f11

También podría gustarte