Caros pmlm e rmendes08, obrigado pela contribuição!
Concordo com os dois, também acho que uma SQL bem feita poderia resolver, como acho que se o banco de dados que foi projetado, tivesse sido de fato projetado, minha consulta seria muito mais rápida e eficiente. O algoritmo é lento pois estou tentando trabalhar com muitos dados ao mesmo tempo, mas ainda assim me descontenta saber que em PHP ele roda em 1 minuto (Em Java está levando 7 minutos).
Para explicar o porquê de eu estar trabalhando com tantos dados, vou dizer duas coisas:
1 - O banco em que a SQL roda, é Interbase 6.1 (mais lento que uma tartaruga bêbada) e a SQL não têm nada super “complexo” justamente para não travar o servidor. Atual SQL:
SELECT M.CDCATEGORIA, M.NUINSCPROF, M.CDTIPO, M.CDTAXA, M.NUPARCELA, M.CDSTATUSP FROM MOVBOLETOS M WHERE M.ANO = 2014 AND ( M.CDCATEGORIA like '01' OR M.CDCATEGORIA like '03' OR M.CDCATEGORIA like '04') AND M.CDTIPO like '04' AND M.NUINSCPROF = (SELECT P.NUINSCPROF FROM PROFISSIONAIS P WHERE M.CDCATEGORIA = P.CDCATEGORIA AND M.CDTIPO = P.CDTIPO AND M.CDSUBTIPO = P.CDSUBTIPO AND M.NUINSCPROF = P.NUINSCPROF AND P.CDSITUACAO = 1 ) ORDER BY M.CDCATEGORIA, M.NUINSCPROF, M.CDTIPO, M.CDTAXA, M.NUPARCELA ASC
Essa SQL acima não demora “nada” em termos de MySql rodando em localhost:8080, sempre demorando por volta de 5 segundos. Porém, como ela deve rodar no banco InterBase fazê-la ainda mais complexa seria um tiro no pé visto que nos meus testes, o Banco InterBase em localhost demorou 3 minutos para rodar a SQL acima, e no servidor demorou eternos 20 minutos. Com esse tempo de execução para essa SQL, não consigo imaginar separá-la em duas, ou aumentar sua complexidade…
2 - Os dados que preciso trabalhar envolvem boletos, e eu preciso verificar por chave composta (sim, não há uma chave primária decente nessa tabela) pelos campos “M.CDCATEGORIA, M.NUINSCPROF, M.CDTIPO, M.CDTAXA”. É preciso verificar se, para cada chave, há algum registro não pago e de qual CDCATEGORIA é (01,03 ou 04), correspondendo à tipos de profissionais diferentes.
O desempenho da lógica, antes de implementar os Iterator que falei no post anterior era
11 à 19 minutos para finalizar, após o Iterator, caiu para 5 à 8 minutos. Não tem como não dar crédito ao remove() da Collection Iterator, porém, ainda assim, o PHP deu um banho de performance, não na SQL, mas na hora de executar a lógica, mesmo sem o Iterator, com o uso de for()
Se eu levar em consideração que estou trabalhando com Java Desktop, não consigo entender o porquê da performance ser pior que a do PHP… Para vocês verem que não estou de “sacanagem”, a lógica do código em Java foi passada num dos meus últimos posts da página 2, e agora vou passar a lógica do PHP:
Obs.: a grande diferença dos códigos é que, não fiz tantos tratamentos em JAVA (o código Java ficou bem mais simples para descobrir se foi pago ou não o boleto) e usei arrays bidimensionais e tridimensionais no caso do PHP
Obs2.: veja o código abaixo somente se não acreditar que a mesma lógica possui 700% de performance melhorada em PHP
//variaveis globais dessa página
//ENFERMEIROS:
$enf_num=0;
$enf_pago=0;
$enf_naopago=0;
//TÉCNICOS:
$tec_num=0;
$tec_pago=0;
$tec_naopago=0;
//AUXILIAR:
$aux_num=0;
$aux_pago=0;
$aux_naopago=0;
//TOTAIS
$tot_num=0;
$tot_pago=0;
$tot_naopago=0;
$sql_boletos="
SELECT `M`.`NUINSCPROF`, `M`.`CDCATEGORIA`, `M`.`CDTIPO`,
`M`.`CDTAXA`,`M`.`NUPARCELA`, `M`.`CDSTATUSP`
FROM `movboletos` as M
WHERE
`M`.`ANO` = 2014 AND (
`M`.`CDCATEGORIA` like '01' OR
`M`.`CDCATEGORIA` like '03' OR
`M`.`CDCATEGORIA` like '04'
)
AND
`M`.`CDTIPO` like '04' AND
`M`.`NUINSCPROF` = (
SELECT `P`.`NUINSCPROF` FROM `profissionais` as P
WHERE `M`.`CDCATEGORIA` = `P`.`CDCATEGORIA` AND
`M`.`CDTIPO` = `P`.`CDTIPO` AND
`M`.`CDSUBTIPO` = `P`.`CDSUBTIPO` AND
`M`.`NUINSCPROF` = `P`.`NUINSCPROF` AND
`P`.`CDSITUACAO` = 1 )
ORDER BY
`M`.`CDCATEGORIA`, `M`.`NUINSCPROF`, `M`.`CDTIPO`,
`M`.`CDTAXA`, `M`.`NUPARCELA` ASC
";
//executa a consulta no banco
$qry_boletos= mysql_query($sql_boletos);
//variaveis de controle
$taxas = array();
$boletos = array();
$atual=0; //salva as infos do último profissional verificado
//varre os dados gerados pela SQL
while($linha = mysql_fetch_array($qry_boletos)){
//define uma variavel como "chave" para separar em conjuntos cada uma das taxas. É como se fosse o "código do boleto"
$chave = $linha['NUINSCPROF'].$linha['CDCATEGORIA'].$linha['CDTIPO'].$linha['CDTAXA'];
//se a chave atual for diferente da anterior, é outro boleto, portanto mais uma anuidade/multa foi acrescentada
if($atual != $chave ){
//verifica qual variavel deve receber valor de acordo com a categoria do boleto
if($linha['CDCATEGORIA']==1){ ++$enf_num; }
if($linha['CDCATEGORIA']==3){ ++$tec_num; }
if($linha['CDCATEGORIA']==4){ ++$aux_num; }
//array recebe um novo indice que corresponde a uma chave, ou, à um novo boleto/taxa/anuidade/multa gerada
$taxas[]=$chave;
}
$boletos[$chave][] = array(
"NUINSCPROF"=>$linha['NUINSCPROF'], //CHAVES: numero da inscrição
"CDCATEGORIA"=>$linha['CDCATEGORIA'], // código da categoria
"CDTIPO"=>$linha['CDTIPO'], // código do tipo de profissional
"CDTAXA"=>$linha['CDTAXA'], //BOLETO: código da taxa - 0 (anuidade), 7 e 8 (multas)
"NUPARCELA"=>$linha['NUPARCELA'], // numero da parcela (0 é única - podendo ser 1,2,3..)
"CDSTATUSP"=>$linha['CDSTATUSP'], // cod Status pagamento (!=NULL > PAGO, Resto > NÃO PAGO)
);
//seta esse valor para variável, para verificar no próximo registro se ainda estamos tratando do mesmo boleto
$atual = $linha['NUINSCPROF'].$linha['CDCATEGORIA'].$linha['CDTIPO'].$linha['CDTAXA'];
}
//varre de taxa em taxa
for($i=0;$i<sizeof($taxas);$i++){
//variável $chave armazena o "código do boleto", formada pelo núm inscrição + cód. categoria + cód. taxa
$chave = $taxas[$i];
//varre os registros do array movboletos no ano definido no for anterior
for($x=0;$x<sizeof($boletos[$chave]);$x++){
//se anuidade (taxa=0), parcela cheia (numparcela=0) e foi paga (CDSTATUSP!=NULL), diga que já está pago
if( $boletos[$chave][$x]['CDTAXA']==0 && $boletos[$chave][$x]['NUPARCELA']==0 && $boletos[$chave][$x]['CDSTATUSP']!=NULL){
//soma como mais um boleto pago
//verifica qual variavel deve receber valor de acordo com a categoria do boleto
//varre os lancamentos dessa taxa para verificar se não há outra parcela não paga
$todasParcelasPagas=true;
for($z=0;$z<sizeof($boletos[$chave]);$z++){
//se cdstatusp==NULL (não paga)
if($boletos[$chave][$z]['CDSTATUSP']==NULL){
//seta a var $todasParcelasPagas como false pois nem todas parcelas foram pagas
$todasParcelasPagas=false;
}
}
//se $todasParcelasPagas=true então soma como mais uma taxa paga
if($todasParcelasPagas){
//soma mais uma PAGA
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_pago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_pago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_pago; }
}else{
//soma mais uma NÃO paga
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_naopago; }
}
//sai desse for, indo para próxima taxa
break;
}
//esse if foi feito para encontrar o caso raro que ocorre quando há somente uma parcela única (cdtaxa=0), não paga e nenhuma outra parcela, nesse caso, apenas verificamos se é isso mesmo e adicionamos como mais um registro não pago
if( $boletos[$chave][$x]['CDTAXA']==0 && $boletos[$chave][$x]['NUPARCELA']==0 && $boletos[$chave][$x]['CDSTATUSP']==NULL){
//se o núm. de registros dessa chave for < 2, quer dizer que só há um único registro,portanto, some
if(sizeof($boletos[$chave])<2){
//soma mais um boleto não pago
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_naopago; }
}
}
//se anuidade (taxa=0) e parcela normal (numparcela!=0)
if( $boletos[$chave][$x]['CDTAXA']==0 && $boletos[$chave][$x]['NUPARCELA']!=0){
//var de controle
$todasParcelasPagas=true;
//for que varre o array desta anuidade p/ verificar se todas parcelas foram pagas
for($z=0;$z<sizeof($boletos[$chave]);$z++){
//se nuparcela!=0 (parcela normal) e cdstatusp==NULL (não paga)
if($boletos[$chave][$z]['NUPARCELA']!=0 && $boletos[$chave][$z]['CDSTATUSP']==NULL){
//seta a var $todasParcelasPagas como false pois nem todas parcelas foram pagas
$todasParcelasPagas=false;
}
}
//se $todasParcelasPagas=true então soma como mais uma taxa paxa
if($todasParcelasPagas){
//soma mais uma PAGA
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_pago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_pago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_pago; }
}else{
//soma mais uma NÃO paga
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_naopago; }
}
//sai desse for, indo para próxima taxa
break;
}
//qualquer taxa em que cdtaxa!=0 não é preciso nenhuma outra verificação, só se verifica se o == e != NULL
if( $boletos[$chave][$x]['CDTAXA']!=0) {
if($boletos[$chave][$x]['CDSTATUSP']!=NULL){
//soma mais uma PAGA
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_pago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_pago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_pago; }
}
if($boletos[$chave][$x]['CDSTATUSP']==NULL){
//soma mais uma NÃO paga
if($boletos[$chave][$x]['CDCATEGORIA']==1){ ++$enf_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==3){ ++$tec_naopago; }
if($boletos[$chave][$x]['CDCATEGORIA']==4){ ++$aux_naopago; }
}
//sai desse for, indo para próxima taxa
break;
}
}//fim 2º FOR
}//fim 1º FOR
//efetua o cálculo do total
$tot_num=$enf_num+$tec_num+$aux_num;
$tot_pago=$enf_pago+$tec_pago+$aux_pago;
$tot_naopago=$enf_naopago+$tec_naopago+$aux_naopago;