Jump to content
Sign in to follow this  
Carlos Rocha

Divisão de loop

Recommended Posts

Carlos Rocha

Pessoal, preciso de uma orientação.

Estou abrindo um arquivo que possui n linhas.

Cada linha possui uma estrutura assim:

dado_a|dado_b|dado_c|dado_d|dado_e

Todos separados por | n linhas assim.

Esse arquivo tem mais de 7000 linhas onde o php precisa verificar linha por linha e comparar se há um combinação de cada linha com uma tabela na base.

Acontece que essa verificação esta sendo feita ok. Porem quando verificada, é preciso fazer um update no banco a partir dos dados lidos no arquivo. Até 3000 e poucas linhas, o update vai bem. Depois trava a pagina.

Gostaria de arranjar uma forma de dividir essa tarefa em um numero que permitisse que o processo não parasse por excesso tempo.

Alguma orientação?

Eis o código atual.

$diretorio = "estoque/";
//Fizemos todos os testes e esta tudo certo.
$arq = fopen($diretorio.$nome,'r'); // abre arquivo
//LÊ O ARQUIVO ATÉ CHEGAR AO FIM
while($linha = fgets($arq))  // Lê linha por linha
{  
$linha_cada = explode('|', $linha);

$busca_string= "
select
estoque.id_estoque,
estoque.id_produto,
estoque.id_cor,
estoque.id_tamanho,
produtos.referencia_produtos  
from estoque
inner join produtos on estoque.id_produto = produtos.id_produtos
inner join tamanhos on estoque.id_tamanho = tamanhos.id_tamanhos
inner join cores on estoque.id_cor = cores.id_cores
where
 produtos.referencia_produtos='$linha_cada[0]' and
 cores.nome_cores='$linha_cada[1]' and
 tamanhos.nome_tamanhos='".$linha_cada[2]."'";

$busca_query= $conexao->query($busca_string);

if ($busca_query->num_rows>0)
{
list($id_estoque, $id_produto, $id_cor, $id_tamanho, $referencia_produtos)=$busca_query->fetch_row();
$atualisa_estoque_string =
"update estoque set estoque=".$linha_cada[3]." where id_estoque=".$id_estoque;
$atualisa_estoque_query = $conexao->query($atualisa_estoque_string);
if ($contador%100==0)
{
$conexao->close;
$conexao->init;
}
}
} //FIM DO WHILE

Edited by carcleo

Share this post


Link to post
Share on other sites
Virneto

Se percebi bem...Não divides a tarefa. Aumentas o time limit da execução do php

set_time_limit (240)

vê no manual


"Que inquieto desejo vos tortura, Seres elementares, força obscura? Em volta de que ideia gravitais?" >> Anthero de Quental

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Linuxando.com | ...

Share this post


Link to post
Share on other sites
HappyHippyHippo

feito de cabeça mas deve te dar umas ideias

<html>
 <head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="javascript">
  function do_exec(start, end) {
	$.post("my_exec.php",
		   {start: start, end: end},
		   function(reply) {
			 $('#status').html(end);
			 if (reply == "more") {
			   do_exec(start + end, end + end);
			 }
		   });
  }
  $(document).load(function() { do_exec(0, 100); });
</script>
 </head>
 <body>
<div>status = <span id="status"></span></div>
 </body>
</html>

$start = (int) $_POST['start'];
$end = (int) $_POST['end'];

$diretorio = "estoque/";
$arq = fopen($diretorio. $nome,'r');

while($linha = fgets($arq) && $linha < $end) {
 if ($linha >= $start) {
// do stuff
 }
 $linha++;
}

if ($linha == $end) echo "more";
else				echo "end";

Edited by Rui Carlos

IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
HappyHippyHippo

set_time_limit (240)

resolveu

estava em 0.

Obrigado pessoal.

e quando o ficheiro tiver 14000 ou 28000 linhas ... vais estar sempre a aumentar o time limit ?


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
taviroquai

Este é daqueles casos em que o script PHP deve correr na shell e não pelo apache.

Share this post


Link to post
Share on other sites
scorch

@carcleo Existem formas bastante mais optimizadas de fazer isso. Pelo que eu vi, tu fazes uma query por cada atualização, por que não fazer tudo de uma vez em batch?

http://stackoverflow.com/questions/13232581/php-mysql-batch-update-multiple-values

Ou seja, ias criando a query sql (a string) e no fim executavas a query de uma vez. :)

Posso dizer que uma vez mudei de vários insert para apenas um am batch, e passei de três minutos para alguns milissegundos. Não sei qual será a melhoria no caso do Update, mas certamente será boa. :)


PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Share this post


Link to post
Share on other sites
Carlos Rocha

Assim:

........
if(move_uploaded_file($_FILES["arquivo"]["tmp_name"], $diretorio . $_FILES["arquivo"]["name"]))
{ 
$contador = 1;
$atualisa_estoque_string='';
//LÊ O ARQUIVO ATÉ CHEGAR AO FIM 
while($linha = fgets($arq))  // Lê linha por linha
{ 
$linha_cada = explode('|', $linha);

$busca_string= "
select 
estoque.id_estoque,
estoque.id_produto,
estoque.id_cor,
estoque.id_tamanho,
produtos.referencia_produtos 
from estoque
inner join produtos on estoque.id_produto = produtos.id_produtos
inner join tamanhos on estoque.id_tamanho = tamanhos.id_tamanhos
inner join cores on estoque.id_cor = cores.id_cores
where 
 produtos.referencia_produtos='$linha_cada[0]' and 
 cores.nome_cores='$linha_cada[1]' and 
 tamanhos.nome_tamanhos='".$linha_cada[2]."'";

  $busca_query= $conexao->query($busca_string);
list($id_estoque, $id_produto, $id_cor, $id_tamanho, $referencia_produtos)=$busca_query->fetch_row();
  if ($busca_query->num_rows>0)
{
$atualisa_estoque_string += 
"update estoque set estoque=".$linha_cada[3]." where id_estoque=".$id_estoque;
  }
print $atualisa_estoque_string;
//$atualisa_estoque_query = $conexao->query($atualisa_estoque_string);
} //FIM DO WHILE

echo "<table align=\"center\" width=\"600px\" height=\"600px\"><tr><td align=\"center\" valign=\"middle\">";
echo "Estoque atualizado na base de dados!";
echo "<br /><br />";
echo "Redirecionando em 1 segundos...";
echo "</td></tr></table>";
header("refresh: 1; url=?acao=form");     
}
........

Share this post


Link to post
Share on other sites
scorch

Seria mais assim:

$ids = array();
$atualisa_estoque_string = 'UPDATE estoque SET estoque = (CASE id_estoque ';
while($linha = fgets($arq)){  // Lê linha por linha
//...
   if ($busca_query->num_rows > 0){
	$atualisa_estoque_string .= ' WHEN '.$id_estoque.' THEN '.$linha_cada[3].' ';
   $ids[] = $id_estoque;
   }
}
$atualisa_estoque_string .= ' ELSE estoque END) WHERE id IN ('.implode(', ', $ids).')';
$conexao->query($atualisa_estoque_string);

Não coloquei o código todo, apenas aquele que alterei. O comentário com os três pontos é o código que já tens, que não modifiquei. :)

Não testei, mas em principio será algo assim parecido.

Edited by scorch

PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Share this post


Link to post
Share on other sites
Carlos Rocha

Pois é, mas olha o que acontece:

$atualisa_estoque_string .= ' WHEN '.$id_estoque.' THEN '.$linha_cada[3].' ';

toda vez que isso passa no while, ele pega essa linha e concatena com ela mesma de novo e pega a preoxima fica alguma coisa assim:

maria

maria jose

maria jose pedro

em vez de sair

maria jose pedro.

entende?

Pois os ids mudam

Edited by Rui Carlos

Share this post


Link to post
Share on other sites
scorch

Experimentou executar a query e ver se funciona? É que esse é o comprotamento esperado (eu sei que ele faz isso).

Se analizar a query, pode ver que ele faz algo parecido: WHEN id_estoque THEN linha[3]. Ou seja, o MySQL vai colocar o valor linha dependendo do id_estoque que for, para cada ID põe o valor correspondente, isto numa só query. :)


PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Share this post


Link to post
Share on other sites
Carlos Rocha

Assim?

<?php
......
if(move_uploaded_file($_FILES["arquivo"]["tmp_name"], $diretorio . $_FILES["arquivo"]["name"]))
{
$atualisa_estoque_string = 'UPDATE estoque SET estoque = CASE id_estoque ';

//LÊ O ARQUIVO ATÉ CHEGAR AO FIM
while($linha = fgets($arq))  // Lê linha por linha
{
$linha_cada = explode('|', $linha);

$busca_string= "
select
estoque.id_estoque,
estoque.id_produto,
estoque.id_cor,
estoque.id_tamanho,
produtos.referencia_produtos
from estoque
inner join produtos on estoque.id_produto = produtos.id_produtos
inner join tamanhos on estoque.id_tamanho = tamanhos.id_tamanhos
inner join cores on estoque.id_cor = cores.id_cores
where
 produtos.referencia_produtos='$linha_cada[0]' and
 cores.nome_cores='$linha_cada[1]' and
 tamanhos.nome_tamanhos='".$linha_cada[2]."'";

$busca_query= $conexao->query($busca_string);

list($id_estoque, $id_produto, $id_cor, $id_tamanho, $referencia_produtos)=$busca_query->fetch_row();

if ($busca_query->num_rows>0)
{
$atualisa_estoque_string .= ' WHEN '.$id_estoque.' THEN '.$linha_cada[3].' ';
}
 } //FIM DO WHILE
 $atualisa_estoque_string .= ' END';
 print $atualisa_estoque_string;
 $atualisa_estoque_query = $conexao->query($atualisa_estoque_string);

 echo "<table align=\"center\" width=\"600px\" height=\"600px\"><tr><td align=\"center\" valign=\"middle\">";
 echo "Estoque atualizado na base de dados!";
 echo "<br /><br />";
 echo "Redirecionando em 1 segundos...";
 echo "</td></tr></table>";
//header("refresh: 1; url=?acao=form");	
}
  else
  {
 echo "<table align=\"center\" width=\"600px\" height=\"600px\"><tr><td align=\"center\" valign=\"middle\">";
 echo "Aconteceu um erro impevisto.<br>Tente novamente!";
 echo "<br /><br />";
 echo "Redirecionando em 1 segundos...";
 echo "</td></tr></table>";
 header("refresh: 1; url=?acao=form");
  }  

 fclose ($arq);  
 $conexao->close();
 }
............

É porque esta dando erro.

Não seria o caso da linha:

$atualisa_estoque_string .= ' WHEN '.$id_estoque.' THEN '.$linha_cada[3].' ';

ser

$atualisa_estoque_string .= ' WHEN '.$id_estoque.' THEN '.$linha_cada[3].' and ';

?

Edited by carcleo

Share this post


Link to post
Share on other sites
scorch

Quase. Eu fiz uma alteração logo após ter submetido o meu post, e se calhar ainda apanhaste a versão antiga, mas se olhares agora vês que faltam ai umas coisitas, tirando isso, sim é esse o código. Como disse, não testei, mas na teoria deve funcionar. :)


PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Share this post


Link to post
Share on other sites
scorch

Que erro? Sem saber qual o erro, é dificil ajudar. :)


PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Share this post


Link to post
Share on other sites
Carlos Rocha

No chome diz só assim:

Nenhum dado foi recebido

Não é possível carregar a página da web porque o servidor não enviou os dados.

Atualize esta página da Web.

Pressione o botão "Atualizar" para reenviar os dados necessários para carregar a página.

Código de erro: ERR_EMPTY_RESPONSE

E no titulo da pagina esta assim: Falha ao carregar http.........

Edited by carcleo

Share this post


Link to post
Share on other sites
scorch

De certeza que o servidor está ligado? O URL da página está correcto? É que esse erro, quase de certeza que não tem nada a ver com código PHP. Experimenta fazer um echo que qualquer coisa logo ao inicio e vê se o Chrome recebe.


PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Share this post


Link to post
Share on other sites
Carlos Rocha

Deu uma parado no codigo quando for até a 30 iteração do while e retornou assim na string

UPDATE estoque SET estoque = (CASE id_estoque

WHEN 4788 THEN 0

WHEN 4790 THEN 0

WHEN 4789 THEN 0

WHEN 4791 THEN 0

WHEN 603 THEN 0

WHEN 608 THEN 0

WHEN 613 THEN 1

WHEN 618 THEN 0

WHEN 623 THEN 0

WHEN 604 THEN 0

ELSE estoque END)

WHERE id IN (4788, 4790, 4789, 4791, 603, 608, 613, 618, 623, 604)

Acho que tem erro de sql ai. Tem não?

Edited by carcleo

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.