Ok. Vamos lá. Faça um teste Euler. Execute /*SELECT* * *FROM*
[tabela]* WHERE *[tabela].[chave] = '1.0'::NUMERIC;/
Sei que era para o Euler fazer o teste mas eu não resisti. Para
começar, que cast mais desnecessário é este que fizestes?? Não seria
mais simples e inteligente algo como:
"select * from tabela where chave = 1.0;"
De preferência em uma tabela onde hajam mais de 1000 registros. Em
seguida, execute a mesma consulta, mas comparando com um inteiro.
Como você informa 1000 registros eu criei uma tabela com 50000 para que
ficasse mais claro esta gritante diferença que o terrível numeric
causaria nas minhas consultas. É claro que eu também me preparei com uma
garrafa de café para passar a noite aqui esperando o retorno delas e
também já avisei minha namorada que eu não iria para casa tão cedo.
Criei a tabela assim:
novo=# create table tablefoo(anytext varchar(100), valor numeric(6,3));;
CREATE TABLE
novo=# create index tablefoo_idx1 on tablefoo(valor);
CREATE INDEX
E gerei os 50000 valores aleatórios com um pequeno script em php assim:
<?php
include "../inc/class/Conexao.inc";
$db = new Conexao();
$db->beginTransaction();
for($i = 0; $i <= 50000; $i++){
$foo = mt_rand(0,10);
$bar = mt_rand(0,999);
$sql = "insert into tablefoo(anytext, valor) values('iteration $i',
$foo.$bar);";
$db->query($sql);
}
$db->commit();
?>
Oh.... é muuuuuuuuuuuuito mais lenta. Porquê? A (excelente)
Para verificar os tempos de resposta eu ativei o timing
novo=# \timing
Timing is on.
Avisei a todos no meu icq e gtalk que eu ficaria off por cerca de 20h
para alguns testes de performance na minha máquina.
novo=# select * from tablefoo where valor = 1.345;
anytext | valor
-----------------+-------
iteration 9094 | 1.345
iteration 10389 | 1.345
iteration 42065 | 1.345
(3 rows)
Time: 0.470 ms
novo=# select * from tablefoo where valor = '1.345'::numeric;
anytext | valor
-----------------+-------
iteration 9094 | 1.345
iteration 10389 | 1.345
iteration 42065 | 1.345
(3 rows)
Time: 0.477 ms
novo=#
Realmente seu casting deixou minha consulta 7 milhonésimos de segundo
mais lenta. Vamos ver casting para float para ter certeza que ele é
lento, parece que não vai dar tempo nem para tomar um café, quanto mais
a garrafa que eu preparei:
novo=# select * from tablefoo where valor = '1.345'::float;
anytext | valor
-----------------+-------
iteration 9094 | 1.345
iteration 10389 | 1.345
iteration 42065 | 1.345
(3 rows)
Time: 90.041 ms
Agora já temos uma enorme diferença, 90 milésimos de segundo.
Vamos pegar a parte inteira de todos os 50000 registros para ver se eu
consigo demorar mais tempo, pelo menos até tomar uma dose de café.
novo=# \o lixo.txt
novo=# select anytext, round(valor) from tablefoo;
Time: 90.500 ms
Poxa, 90 milésimos de segundo para arredondar 50000 registros numéric.
Então vamos tentar converter para o tipo varchar
novo=# select anytext, valor::varchar from tablefoo;
Time: 109.672 ms
Retirar somente a parte inteira dos 50000 registros;
novo=# select anytext, trunc(valor) from tablefoo;
Time: 129.208 ms
Desisto, não vou ter tempo nem para tomar um cafezinho. O PostgreSql
insiste em tratar os 50000 registros com dados numeric em menos de um
décimo de segundo.
Ainda sem fundamento?
Sinto muito cara, mas infelizmente sim.
Para compor um único registro eram feitas em torno de 10 consultas
dessa forma, além das 2 consultas de auto-referência (na mesma tabela
haviam, eventualmente, o "pai" e a "mãe" do mesmo).
Como eu disse, limitação do ambiente, da tecnologia, do seu script de
migração, de falta de modelagem, de qualquer outra coisa que você sonhar
no mundo, menos do PostGreSql. Portanto eu peço que não envie mensagens
com afirmações infundadas e distorcidas para o grupo pois pode
prejudicar quem está começando agora no PostGreSql.
Assim, os 378,998 registros, sem o cuidado de usar um cast para tipo
inteiro (primeira versão da função) demorou em torno de 20 horas. Após a
otimização foram menos de 2 minutos.
Infelizmente não posso lhe mostrar os dados, mas GARANTO que, tanto
num 8.2 quanto num 8.3, você poderá experimentar a diferença no tempo
simplesmente comparando uma constante numeric com uma constante integer.
Opa, isto eu não tinha tentado ainda, vamos lá;
novo=# select * from tablefoo where valor = 1;
anytext | valor
-----------------+-------
iteration 21263 | 1.000
iteration 34970 | 1.000
iteration 37109 | 1.000
iteration 42379 | 1.000
iteration 43073 | 1.000
(5 rows)
Time: 3.568 ms
Poxa, 3 milesegundos comparando com inteiros! Desisto cara, você fez
mágica com sua rotina de migração. Ja liguei para minha namorada e disse
que agente vai poder se ver, ela pediu para te agradecer, agora ainda
estou triste por estragar uma garrafa inteira de cafezinho. Ao menos
tomei um agora no final.
Abraço,
--
Shander Lyrio