Olá Vitellozi,
Eu sugiro você substituir a function por um cálculo direto no SQL, por questão de performance. No SQL postado acima há
12 chamadas para a função, e isso acrescenta um peso enorme no SQL fazendo chaveamento de contexto entre a engine SQL e a PL/SQL, para algo que dá para resolver apenas no SQL da forma abaixo:
Selecionar tudo
SELECT CDSEXO,
CASE
WHEN IDADE BETWEEN 0 AND 18 THEN 1 -- F 3695 M 3833
WHEN IDADE BETWEEN 19 AND 23 THEN 2
WHEN IDADE BETWEEN 24 AND 28 THEN 3
WHEN IDADE BETWEEN 29 AND 33 THEN 4
WHEN IDADE BETWEEN 24 AND 59 THEN 5
WHEN IDADE > 59 THEN 6
END FAIXA,
COUNT(*)
FROM (SELECT u.*,
trunc(months_between(sysdate, P.DTNASCIMENTO) / 12) as idade,
p.cdsexo,
p.dtnascimento
FROM USUARIO U
JOIN PESSOA P on U.NRREGISTRO_USUARIO = P.NRREGISTRO AND P.CDSEXO IS NOT NULL) u
GROUP BY CDSEXO,
CASE
WHEN IDADE BETWEEN 0 AND 18 THEN 1
WHEN IDADE BETWEEN 19 AND 23 THEN 2
WHEN IDADE BETWEEN 24 AND 28 THEN 3
WHEN IDADE BETWEEN 29 AND 33 THEN 4
WHEN IDADE BETWEEN 24 AND 59 THEN 5
WHEN IDADE > 59 THEN 6 END
Abaixo faço um teste de desempenho comparando:
Selecionar tudo
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.5.0
Connected as FSITJA
SQL>
SQL> CREATE OR REPLACE FUNCTION idade(pdtnasc IN DATE, pdtrefer IN DATE) RETURN NUMBER AS
2 vnrdiar VARCHAR2(2);
3 vnrmesr VARCHAR2(2);
4 vnranor VARCHAR2(4);
5 vnrdian VARCHAR2(2);
6 vnrmesn VARCHAR2(2);
7 vnranon VARCHAR2(4);
8 vlresult NUMBER(04);
9 BEGIN
10 vnrdian := to_char(pdtnasc, 'dd');
11 vnrmesn := to_char(pdtnasc, 'mm');
12 vnranon := to_char(pdtnasc, 'yyyy');
13 vnrdiar := to_char(pdtrefer, 'dd');
14 vnrmesr := to_char(pdtrefer, 'mm');
15 vnranor := to_char(pdtrefer, 'yyyy');
16 IF vnrmesr || vnrdiar >= vnrmesn || vnrdian
17 THEN
18 vlresult := to_number(vnranor) - to_number(vnranon);
19 ELSE
20 vlresult := to_number(vnranor) - to_number(vnranon) - 1;
21 END IF;
22 IF vlresult > 0
23 THEN
24 RETURN vlresult;
25 ELSE
26 RETURN 0;
27 END IF;
28 END;
29 /
Function created
SQL> create table usuario as
2 select level as nrregistro_usuario
3 from dual connect by level <= 1000000;
Table created
SQL> create table pessoa as
2 select level as nrregistro,
3 trunc(sysdate - level) as dtnascimento,
4 decode(trunc(dbms_random.value*2), 0, 'M', 'F') as cdsexo
5 from dual connect by level <= 1000000;
Table created
SQL> set serveroutput on
SQL> DECLARE
2 t1 NUMBER;
3 t2 NUMBER;
4 qtty NUMBER;
5 BEGIN
6 -- executa para carregar no buffer e realizar parse
7 select count(*) into qtty from (
8 SELECT P.CDSEXO,
9 CASE
10 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 0 AND 18 THEN 1 -- F 3695 M 3833
11 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 19 AND 23 THEN 2
12 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 28 THEN 3
13 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 29 AND 33 THEN 4
14 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 59 THEN 5
15 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) > 59 THEN 6
16 END FAIXA,
17 COUNT(1)
18 FROM USUARIO U, PESSOA P
19 WHERE U.NRREGISTRO_USUARIO = P.NRREGISTRO AND P.CDSEXO IS NOT NULL
20 GROUP BY P.CDSEXO,
21 CASE
22 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 0 AND 18 THEN 1
23 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 19 AND 23 THEN 2
24 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 28 THEN 3
25 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 29 AND 33 THEN 4
26 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 59 THEN 5
27 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) > 59 THEN 6 END);
28
29 t1 := dbms_utility.get_time;
30 select count(*) into qtty from (
31 SELECT P.CDSEXO,
32 CASE
33 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 0 AND 18 THEN 1 -- F 3695 M 3833
34 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 19 AND 23 THEN 2
35 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 28 THEN 3
36 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 29 AND 33 THEN 4
37 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 59 THEN 5
38 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) > 59 THEN 6
39 END FAIXA,
40 COUNT(1)
41 FROM USUARIO U, PESSOA P
42 WHERE U.NRREGISTRO_USUARIO = P.NRREGISTRO AND P.CDSEXO IS NOT NULL
43 GROUP BY P.CDSEXO,
44 CASE
45 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 0 AND 18 THEN 1
46 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 19 AND 23 THEN 2
47 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 28 THEN 3
48 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 29 AND 33 THEN 4
49 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) BETWEEN 24 AND 59 THEN 5
50 WHEN IDADE(P.DTNASCIMENTO, SYSDATE) > 59 THEN 6 END);
51 t2 := dbms_utility.get_time;
52 dbms_output.put_line(qtty || ' registros em ' || to_char((t2 - t1) / 100, '990.000') || ' segundos');
53 -- executa para carregar no buffer e realizar parse
54 select count(*) into qtty from (
55 SELECT CDSEXO,
56 CASE
57 WHEN IDADE BETWEEN 0 AND 18 THEN 1 -- F 3695 M 3833
58 WHEN IDADE BETWEEN 19 AND 23 THEN 2
59 WHEN IDADE BETWEEN 24 AND 28 THEN 3
60 WHEN IDADE BETWEEN 29 AND 33 THEN 4
61 WHEN IDADE BETWEEN 24 AND 59 THEN 5
62 WHEN IDADE > 59 THEN 6
63 END FAIXA,
64 COUNT(*)
65 FROM (SELECT u.*,
66 trunc(months_between(sysdate, P.DTNASCIMENTO) / 12) as idade,
67 p.cdsexo,
68 p.dtnascimento
69 FROM USUARIO U
70 JOIN PESSOA P on U.NRREGISTRO_USUARIO = P.NRREGISTRO AND P.CDSEXO IS NOT NULL) u
71 GROUP BY CDSEXO,
72 CASE
73 WHEN IDADE BETWEEN 0 AND 18 THEN 1
74 WHEN IDADE BETWEEN 19 AND 23 THEN 2
75 WHEN IDADE BETWEEN 24 AND 28 THEN 3
76 WHEN IDADE BETWEEN 29 AND 33 THEN 4
77 WHEN IDADE BETWEEN 24 AND 59 THEN 5
78 WHEN IDADE > 59 THEN 6 END);
79 t1 := dbms_utility.get_time;
80 select count(*) into qtty from (
81 SELECT CDSEXO,
82 CASE
83 WHEN IDADE BETWEEN 0 AND 18 THEN 1 -- F 3695 M 3833
84 WHEN IDADE BETWEEN 19 AND 23 THEN 2
85 WHEN IDADE BETWEEN 24 AND 28 THEN 3
86 WHEN IDADE BETWEEN 29 AND 33 THEN 4
87 WHEN IDADE BETWEEN 24 AND 59 THEN 5
88 WHEN IDADE > 59 THEN 6
89 END FAIXA,
90 COUNT(*)
91 FROM (SELECT u.*,
92 trunc(months_between(sysdate, P.DTNASCIMENTO) / 12) as idade,
93 p.cdsexo,
94 p.dtnascimento
95 FROM USUARIO U
96 JOIN PESSOA P on U.NRREGISTRO_USUARIO = P.NRREGISTRO AND P.CDSEXO IS NOT NULL) u
97 GROUP BY CDSEXO,
98 CASE
99 WHEN IDADE BETWEEN 0 AND 18 THEN 1
100 WHEN IDADE BETWEEN 19 AND 23 THEN 2
101 WHEN IDADE BETWEEN 24 AND 28 THEN 3
102 WHEN IDADE BETWEEN 29 AND 33 THEN 4
103 WHEN IDADE BETWEEN 24 AND 59 THEN 5
104 WHEN IDADE > 59 THEN 6 END);
105 t2 := dbms_utility.get_time;
106 dbms_output.put_line(qtty || ' registros em ' || to_char((t2 - t1) / 100, '990.000') || ' segundos');
107 end;
108 /
12 registros em 154.380 segundos
12 registros em 31.960 segundos
PL/SQL procedure successfully completed
SQL> drop table usuario;
Table dropped
SQL> drop table pessoa;
Table dropped
Como você pode ver, para 1 milhão de registros de usuário/pessoa, o desempenho fica 5 vezes melhor:
154.380 segundos com functions
x
31.960 segundos sem functions .
Abraço,
Francisco.