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

andrepcg

Melhorar velocidade de SELECT e INSERT

Mensagens Recomendadas

andrepcg

tenho este código php que criei. como não sou bom em optimizações, tenho a certeza que deve haver uma maneira muito melhor de fazer isto. por isso peço a vossa ajuda.

um utilizador pega numa lista de, imaginemos, 1000 palavras, separadas por uma linha, e submete no formulário. o que o script faz é pegar em cada linha (foreach), fazer select e verificar se está na base de dados, e se não estiver, insere na BD. portanto, com 1000 palavras tem de repetir esta acção 1000 vezes o que demora imenso e consome recursos.

foreach ($lines as $line) {
              
              if(preg_match('/^[a-f0-9]{32}.)/', $line) == 1){
           

              $parts = explode(':', $line, 2);
              $md5hash = strtolower(trim($parts[0]));
              $decrypted_pass = addslashes($parts[1]);
              
              $encoded = base64_encode($decrypted_pass);
  
              $sql = mysql_query("SELECT md5_hash, decrypted FROM hashes WHERE md5_hash='$md5hash' AND decrypted='$encoded'") or die(mysql_error());
              $sql2 = mysql_num_rows($sql);
              
              $md5_check = md5($decrypted_pass);
              
               if(($sql2 == 0) && ($md5_check == $md5hash)){
                     $total  ;
                     
                     $query_log = mysql_query("INSERT INTO hashes (md5_hash, decrypted) VALUES('$md5hash','$encoded')") or die(mysql_error());
                     
               }
               
              }
           }

qual é a melhor maneira de melhorar o codigo de modo que seja muito mais rapido e eficaz?

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

Há duas maneiras para ficar mais rápido:

1. usar transacções;

2. usar inserções "em massa" - bastante melhor. Verifica se este post te ajuda (tens de andar alguns para cima e para baixo para perceber de que é que se estava a falar).


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
andrepcg

ok obrigado. já agora, o que sao transacçoes?

fiz este rascunho de codigo prque preciso de alguma ajuda a formatar o meu codigo para funcionar como dizes. sei que neste codigo muita coisa esta mal mas preciso de luzes a trabalhar desta nova maneira.

// divide cada linha e remove duplicados
$lines = array_unique(explode("\n", $hashes));
             
		 //verifica se cada linha confirma o preg_match
         if(preg_match('/^[a-f0-9]{32}.)/', $line) == 1){
           
			$sql_novos = "INSERT IGNORE INTO hashes ";

			$sql = $sql_novos . "(md5_hash, decrypted) VALUES ";
  
		  $parts = explode(':', $line, 2);
		  $md5hash = strtolower(trim($parts[0]));
		  $decrypted_pass = addslashes($parts[1]);

		  $encoded = base64_encode($decrypted_pass);
  
		  $md5_check = md5($decrypted_pass);

		   if($md5_check == $md5hash){

				 while(($linha = $lines) !== false)
   				 $sql .= "(" . $md5hash . ", '" . $encoded . "'), ";

			 $sql = rtrim($sql, ", ");

			$resSQL = mysql_query($sql);
			// se $resSQL == true, foram enfiados com sucesso, se não... tem gato...

		   }
               
         }

aquilo estava feito para trabalhar com o foreach e foi dificil para mim adaptar ao novo formato por isso nao alterei assim muita coisa. espero que me possam ajudar

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

A questão não está no foreach vs. while, podes usar o que te der mais jeito; o truque está na construção da query, que é em massa.

À partida, é isso, está correcto - excepto as linhas no while, isso era para o problema do OP do outro tópico...


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
andrepcg

ah ok mas então repara:

$lines = array_unique(explode("\n", $hashes));

foreach ($lines as $line) {
             
         if(preg_match('/^[a-f0-9]{32}.)/', $line) == 1){
           

              $parts = explode(':', $line, 2);
              $md5hash = strtolower(trim($parts[0]));
              $decrypted_pass = addslashes($parts[1]);
             
              $encoded = base64_encode($decrypted_pass);

             
              $md5_check = md5($decrypted_pass);
             
               if($md5_check == $md5hash){
                     
                     $query_log = mysql_query("INSERT INTO hashes (md5_hash, decrypted) VALUES('$md5hash','$encoded')") or die(mysql_error());
				 $sql_novos = "INSERT IGNORE INTO tabela ";


				$sql = $sql_novos . "(md5_hash, decrypted) VALUES ";

				$sql .= "(" . $md5hash . ", '" . $encoded . "'), ";

				// isto serve para tirar a última vírgula e espaço da string sql
				$sql = rtrim($sql, ", ");

				$resSQL = mysql_query($sql);
                     
               }
               
         }
}

entao se o problema nao e no foreach, pelo que estou a entender então para cada linha, está a correr novamente cada query individualmente e nao em massa.

peço desculpa mas isto as vezes e complicado quando se está habituado a uma coisa. se me conseguires demonstrar nos parametros do meu script, era mais facil claro.

obrigado pela ajuda

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

Porque não tomaste atenção ao que era realmente importante no outro post...  :smoke:

Repara, já tens as linhas; depois, por cada linha, fazes umas coisitas e queres inserir - mas não precisas de inserir logo, podes inserir só no fim de teres feito tudo o que é suposto, desde que vás adicionando as coisas à query...

Tipo isto:

// inicializar a query string
$sql = "INSERT IGNORE INTO tabela (md5_hash, decrypted) VALUES ";

$lines = array_unique(explode("\n", $hashes));

foreach ($lines as $line)
{
    if(preg_match('/^[a-f0-9]{32}.)/', $line) == 1)
    {
        $parts = explode(':', $line, 2);
        $md5hash = strtolower(trim($parts[0]));
        $decrypted_pass = addslashes($parts[1]);

        $encoded = base64_encode($decrypted_pass);
        $md5_check = md5($decrypted_pass);

        // acrescentar os dados à query
        if($md5_check == $md5hash)
            $sql .= "(" . $md5hash . ", '" . $encoded . "'), ";
    }
}

// limpar a query
$sql = rtrim($sql, ", ");
// executar a query - repara bem: fora do ciclo!
$resSQL = mysql_query($sql);

// convem verificar, com uma flag, por exemplo, se efectivamente existe alguma coisa para inserir

Geez , limpem e tabulem o código correctamente, fica mais fácil de ler e ajudar...

Noutra nota: transacção é uma forma de manipular a BD sem, na realidade, fazer alguma coisa definitivamente, até ser explicitamente chamada a execução de tudo o que foi feito dentro da transacção.


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
andrepcg

obrigado :D agora está a funcionar fixe, mais ou menos.

ja tenho os dados na BD, mas se fizer insert ignore, ele insere outra vez os dados, apesar de eles ja la estarem, precisamente iguais

outra coisa relacionada. qual e a melhor maneira de saber quantos dados foram precisamente inseridos na BD?

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

Qual é a chave primária da tabela? Ou campos únicos?

Se não se aplicar a nenhum dos dois que estás a inserir, então, sim, vai inserir duplicados; mas isso já não é um problema da PHP, mas sim de arquitectura de BD.


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
andrepcg

como primario tenho apenas o ID da row que leva com um auto increment em cima. entao tenho de colocar a md5_hash como PRIMARY e ja deve funcionar, certo? vou experimentar agora

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

como primario tenho apenas o ID da row que leva com um auto increment em cima. entao tenho de colocar a md5_hash como PRIMARY e ja deve funcionar, certo? vou experimentar agora

Não, metes como UNIQUE. A chave primária é a chave primária, deixa estar que está bem...


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
andrepcg

ok, ja está a funcionar bem. outra coisa. no antigo codigo ele somava sempre mais um sempre que ele executava o codigo de inserir na BD. mas ele agora faz aquela cena do IGNORE. como é que posso contar agora quantas das linhas é que foram totalmente inseridas na BD, sem contar obviamente com os duplicados?

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
M6

A forma mais rápida é fazeres inserção em massa pela base de dados com INSERT from SELECT (http://dev.mysql.com/doc/refman/5.1/en/insert-select.html).

Fazes INSERT INTO tabela SELECT (selecção da informação que queres inserir, obviamente incluído filtros e cláusulas de selecção).


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

A forma mais rápida é fazeres inserção em massa pela base de dados com INSERT from SELECT (http://dev.mysql.com/doc/refman/5.1/en/insert-select.html).

Fazes INSERT INTO tabela SELECT (selecção da informação que queres inserir, obviamente incluído filtros e cláusulas de selecção).

Hmmm, como é que isso o ajuda a inserir linhas de um array é que me ultrapassa...

É que nem olhaste para o código...  :smoke:


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

Isso é mais fácil, basta ir acrescentando à clausula WHERE do DELETE os campos que queres apagar, com OR's.


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
M6

Hmmm, como é que isso o ajuda a inserir linhas de um array é que me ultrapassa...

É que nem olhaste para o código...  :smoke:

A solução que dei é a solução genérica para fazer inserção em massa numa base de dados, que aliás era o problema original.


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

A solução que dei é a solução genérica para fazer inserção em massa numa base de dados, que aliás era o problema original.

Ai era? Safa, ou tenho de trocar de óculos, ou a cafeína em excesso atingiu, por fim, a minha capacidade de raciocínio...

um utilizador pega numa lista de, imaginemos, 1000 palavras, separadas por uma linha, e submete no formulário.

Podia jurar que aqui está escrito que existe uma lista externa à base de dados que é para inserir; mas isto sou eu...


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
M6

Após rever os posts, creio que a confusão vem do meu primeiro post onde parece que não me expliquei bem.

Não estava a responder directamente à questão colocada no tópico mas sim apenas a referir a melhor forma de efectuar inserções em massa é sempre através da db, usando por exemplo insert from select.

Neste caso em particular começa-se por se fazer um insert por cada select que, por sua vez é obtido a partir de uma linha de um array. A utilização desta estratégia pode não ser possível, no entanto não quis deixar de mostrar uma forma de inserção em massa que é comummente usada em situações idênticas.


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado
Neste caso em particular começa-se por se fazer um insert por cada select que, por sua vez é obtido a partir de uma linha de um array. A utilização desta estratégia pode não ser possível, no entanto não quis deixar de mostrar uma forma de inserção em massa que é comummente usada em situações idênticas.

Oh, M6, tem lá paciência: olha para o código do OP e interpreta-o.

O SELECT só estava lá para controlo de registos existentes; com o INSERT IGNORE da forma que eu e o andrepcg chegámos à conclusão que seria melhor, já não é necessário e é a forma mais eficaz de resolver o problema.


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
M6

mjamado, desculpa lá se te irritei com um off-topic com informação útil!...


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mjamado

mjamado, desculpa lá se te irritei com um off-topic com informação útil!...

Off-topics com informação útil não me irritam. Irrita-me, isso sim, pessoas que não são capazes de assumir que erraram...

Estamos à meio-dia nisto; se tivesses dito logo "ah, e tal, não tinha percebido bem", já estava o assunto resolvido.


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
M6

ah, e tal, não tinha percebido bem.

Satisfeito? :)


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

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.