Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

carcleo

Divisão de loop

Mensagens Recomendadas

carcleo

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

Editado por carcleo

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Devexz

e não podes por exemplo ler até x linhas, e depois começar a ler mas onde terminaste pela ultima vez?


Ás vezes, mais vale deixar a assinatura em branco.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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 | ...

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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";

Editado por Rui Carlos

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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. :)


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

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");     
}
........

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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.

Editado por scorch

scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

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

Editado por Rui Carlos

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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. :)


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

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 ';

?

Editado por carcleo

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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. :)


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
scorch

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


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

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.........

Editado por carcleo

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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.


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

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?

Editado por carcleo

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
scorch

Está certo, a seguir ao WHERE não devia ser id mas sim id_estoque. :)


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

Veja isso:


	$atualisa_estoque_string = "UPDATE estoque SET estoque = case";

//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 = '".$id_estoque."'
THEN '".$linha_cada[3]."'";
}
 } //FIM DO WHILE
   $atualisa_estoque_string .= " END";
   $conexao->query($atualisa_estoque_string);	
 print $atualisa_estoque_string;

ele iprimiu a seguinte 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
)
END

Mas não rodou

Editado por carcleo

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
scorch

Experimenta correr esse SQL que ele deu diretamente no PHPMyAdmin, e vê se ele executa direito. Já agora, existe alguma coluna chamada estoque? :)


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
carcleo

sim há!

Mas não roda.

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
)
END

dá erro de sintaxe

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
scorch

Ele não pode estar a dar essa query com o código que eu te dei. Se reparares, lá só fecho os parêntesis depois do End, e aí os parentesis aparecem antes do end. Também não aparece aí o ELSE nem o WHERE. De certeza que colocaste o código direito? :)


scorch_pp.png

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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.