Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Jota_Skazi

Query muito lenta

Recommended Posts

Olá,

eu estou com um problema ao executar algumas querys e gostaria de saber se alguém pode me ajudar.

 

O script é o seguinte:

 

<?PHP
$world_id = 0;
$world_name = $config['server']['serverName'];

$order = $_REQUEST['order'];
if($order == 'level')
$orderby = 'level';
elseif($order == 'vocation')
$orderby = 'vocation';
if(empty($orderby))
$orderby = 'name';

$SQL->query("DELETE FROM players_online WHERE level > 0");
//$q_online = mysql_query("SELECT DISTINCT * FROM players WHERE world_id = '".(int) $world_id."' AND online = 1", $cn) or die(mysql_error());
//$pon = mysql_fetch_object($q_online);
$q_online = $SQL->query("SELECT DISTINCT * FROM players WHERE world_id = '".(int) $world_id."' AND online = 1");
$i = 0;
foreach($q_online as $online){
		$SQL->query("INSERT INTO players_online(name, level, vocation, promotion, spoof) 
				VALUES('".addslashes($online['name'])."', '".$online['level']."', '".$online['vocation']."', '".$online['promotion']."', '0')");
		$i++;
}

$limit_spoof = ($config['status']['serverStatus_players'] - $i);

$q_spoof = $SQL->query("SELECT * FROM players WHERE world_id = '".(int) $world_id."' AND online = 0 AND level > 9 and group_id < 2 GROUP BY account_id LIMIT ".$limit_spoof."", $cn);
foreach($q_spoof as $spoof){
		 	$SQL->query("INSERT INTO players_online(name, level, vocation, promotion, spoof) 
				VALUES('".addslashes($spoof['name'])."', '".$spoof['level']."', '".$spoof['vocation']."', '".$spoof['promotion']."', '1')");
}

$players_online_data = $SQL->query('SELECT * FROM players_online ORDER BY '.$orderby);

$number_of_players_online = 0;
foreach($players_online_data as $player) {
$number_of_players_online++;
if(is_int($number_of_players_online / 2))
	$bgcolor = $config['site']['darkborder'];
else
	$bgcolor = $config['site']['lightborder'];

$kills = 6;
$time = 3 * 60 * 60 * 1000;
$hasRs = $kills * $time;
$rs = "";
if ($player['skulltime'] > 0 && $player['skull'] == 0)
	$rs = "<img style='border: 0;' src='./images/whiteskull.gif'/>";
else if ($player['skulltime'] >= $hasRs or $player['skull'] == 1)
	$rs = "<img style='border: 0;' src='./images/redskull.gif'/>";

$players_rows .= '<TR BGCOLOR='.$bgcolor.'><TD WIDTH=70%>'.$player['name'].$rs.'</TD><TD WIDTH=10%>'.$player['level'].'</TD><TD WIDTH=20%>'.$vocation_name[$world_id][$player['promotion']][$player['vocation']].'</TD></TR>';
}
if($number_of_players_online == 0)
//server status - server empty
$main_content .= '<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=4 WIDTH=100%><TR BGCOLOR="'.$config['site']['vdarkborder'].'"><TD CLASS=white><B>Server Status</B></TD></TR><TR BGCOLOR='.$config['site']['darkborder'].'><TD><TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1><TR><TD>Currently no one is playing on <b>'.$config['site']['worlds'][$world_id].'</b>.</TD></TR></TABLE></TD></TR></TABLE><BR>';
else
{

//server status - someone is online
$main_content .= '<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=4 WIDTH=100%><TR BGCOLOR="'.$config['site']['vdarkborder'].'"><TD CLASS=white><B>Server Status</B></TD></TR><TR BGCOLOR='.$config['site']['darkborder'].'><TD><TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1><TR><TD>Currently '.$number_of_players_online.' players are online on <b>'.$config['site']['worlds'][$world_id].'</b>.</TD></TR></TABLE></TD></TR></TABLE><BR>';


$main_content .= "<table width='100%' cellspacing='1'>
	<tr>
		<td style='background: ".$bgcolor.";' align='center'>
			<img src='./images/whiteskull.gif'/> - 1 - 6 Frags
			<br/>
			<img src='./images/redskull.gif'/> - 6+ Frags or Red Skull
		</td>
	</tr>
	</table>";

//list of players
$main_content .= '<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=4 WIDTH=100%><TR BGCOLOR="'.$config['site']['vdarkborder'].'"><TD><A HREF="?subtopic=whoisonline&order=name" CLASS=white>Name</A></TD><TD><A HREF="?subtopic=whoisonline&order=level" CLASS=white>Level</A></TD><TD><A HREF="?subtopic=whoisonline&order=vocation" CLASS=white>Vocation</TD></TR>'.$players_rows.'</TABLE>';
//search bar
$main_content .= '<BR><FORM ACTION="?subtopic=characters" METHOD=post>  <TABLE WIDTH=100% BORDER=0 CELLSPACING=1 CELLPADDING=4><TR><TD BGCOLOR="'.$config['site']['vdarkborder'].'" CLASS=white><B>Search Character</B></TD></TR><TR><TD BGCOLOR="'.$config['site']['darkborder'].'"><TABLE BORDER=0 CELLPADDING=1><TR><TD>Name:</TD><TD><INPUT NAME="name" VALUE=""SIZE=29 MAXLENGTH=29></TD><TD><INPUT TYPE=image NAME="Submit" SRC="'.$layout_name.'/images/buttons/sbutton_submit.gif" BORDER=0 WIDTH=120 HEIGHT=18></TD></TR></TABLE></TD></TR></TABLE></FORM>';
}
?>

 

Este script demora mais ou menos de 15 a 20s para rodar, sendo que a primeira query ($q_online) seleciona cerca de 150 registros e a segunda, $q_spoof, seleciona cerca de 120 registros.

 

Existe alguma maneira de simplificar este script ou então de optimizar algo em meu servidor ?

 

OBS: Uso Ubuntu Server 10.04, processador Quad Xeon 2.4GHz, 8GB RAM.

 

Obrigado

 

Edit: Agora que eu vi que postei na área errada, pff, desculpem-me =x

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá,

 

Conforme o aviso existente no fórum de origem deste post, não é permitida a postagem de dúvidas nesta área, motivo pelo qual este tópico será movido para o fórum principal deste assunto.

 

Tópico Movido

Origem: Artigos, Tutoriais e Matérias (PHP) http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Destino: PHP - Patrocínio: TreinaWeb

Compartilhar este post


Link para o post
Compartilhar em outros sites

Qual é o banco de dados ?

 

MySQL ? SQL Server ?

 

vamos isolar tuas querys:

DELETE FROM players_online WHERE level > 0
é possível alguém com nível < 0 ??

SELECT DISTINCT * FROM players WHERE world_id = '1' AND online = 1
o DISTINCT, é mais rápido, se for chamado com parâmetros, de preferência pelo campo identificador da tabela. Aliás, você precisa dele ai ?

 

o * é 'lento', prefira listar a relação de campos:

SELECT id, nome, ... FROM players..

logo abaixo:

foreach($q_online as $online){
você faz um INSERT...

hum.. já viu subquery ??

 

assim você evitaria esse loop no php, e deixaria a cargo do banco, executando uma só consulta(para selecionar E inserir)

 

cheguei no teu:

$orderby

dava pra melhorar isso:

if($order == 'level')
        $orderby = 'level';
elseif($order == 'vocation')
        $orderby = 'vocation';
if(empty($orderby))
        $orderby = 'name';
ne?!

 

que tal:

$orderby = ( !empty($order) ) ? $order : 'name';
evita esse monte de ifs desnecessários, e não limita tanto a tua qntidade de opções.

 

As outras alterações, já não são 'do banco', veja:

$time = 3 * 60 * 60 * 1000;
isso tem um valor fixo ne?!

então não faz sentido nenhum você executar isso dentro do loop, pois você recalcula a cada iteração, para obter o mesmo valor... ^_^

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado pela sua ajuda.

 

Fiz quase tudo que você me recomendou:

 

Troquei:

if($order == 'level')
$orderby = 'level';
elseif($order == 'vocation')
$orderby = 'vocation';
if(empty($orderby))
$orderby = 'name';

POR:

$orderby = ( !empty($order) ) ? $order : 'name';

 

Troquei:

$SQL->query("DELETE FROM players_online WHERE level > 0");

POR:

$SQL->query("TRUNCATE TABLE players_online");

 

Troquei:

$q_online = $SQL->query("SELECT DISTINCT * FROM players WHERE world_id = '".(int) $world_id."' AND online = 1");

POR:

$q_online = $SQL->query("SELECT DISTINCT id, account_id, name, level, vocation, promotion FROM players WHERE online = 1");

 

Retirei de dentro do foreach:

$kills = 6;
$time = 3 * 60 * 60 * 1000;
$hasRs = $kills * $time;
$rs = "";

 

A propósito, uso MySQL e não entendi muito bem como posso usar a subquery no meu script.

 

Apesar de todas essas mudanças, continua praticamente a mesma lerdeza. =X

Compartilhar este post


Link para o post
Compartilhar em outros sites

tá... você precisa mesmo do DISTINCT ?? parece que não.

remova ele:

$q_online = $SQL->query("SELECT id, account_id, name, level, vocation, promotion FROM players WHERE  online = 1");
se precisar, agrupe ele pelo que diferencia um do outro, algo como:

DISTINCT(account_id)

 

Bom, da subquery, tenho um exemplo aqui:

http://forum.imasters.com.br/index.php?/topic/395754-dados-de-uma-tabela-para-a-outra/page__view__findpost__p__1546306

 

apesar de ser um UPDATE, para o teu INSERT, seria a mesma coisa.

se tiver dúvidas, poste a estrutura das tabelas.

 

Depois de remover o DISTINCT, melhorou o desempenho ?

No caso, o objeto: $SQL, referencia qual classe ? ela foi bem escrita ?

 

usando os mysql_ ou a classe nativa MySQLi ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Na verdade, eu preciso do distinct porque não pode ter NENHUM registro com a account_id repetida, devem ser selecionados somente jogadores com account_id diferente.

 

Troquei por:

 $q_online = $SQL->query("SELECT id, account_id, name, level, vocation, promotion FROM players WHERE online = 1 GROUP BY account_id"); 

 

Ficou perfeito, 0.01s pra execução do script agora kkkk

 

Muito obrigado pela ajuda.

Compartilhar este post


Link para o post
Compartilhar em outros sites

opa! legal! :lol:

 

rodando assim:

SELECT DISTINCT(account_id), id, name, level, vocation, promotion FROM players WHERE online = 1
que desempenho você teve?

 

apenas curiosidade ^_^

Compartilhar este post


Link para o post
Compartilhar em outros sites

Opa, na verdade, eu percebi que eu não consegui resolver o problema =x

 

Eu achei que havia conseguido, pois coincidentemente, eu mudei o script para outro servidor, no caso, um VPS que eu criei em um dedicado.

 

O problema só deixou de ocorrer NESSE vps específico. Se eu coloco o script em qualquer outro servidor, seja windows ou linux, a execução da query continua MUITO lenta.

 

Eu percebi que o problema é ao rodar as querys de INSERT dentro dos foreachs, acontece também com querys de UPDATE.

 

No VPS que o script não fica lento, uso as seguintes versões:

PHP: PHP Version 5.2.6-3ubuntu4.5

MySQL: Client API version 5.0.75

OS: Ubuntu 9.04

 

Em um servidor que ele fica lento, um exemplo do que uso é:

PHP: PHP Version 5.3.2-1ubuntu4.2

MySQL: Client API version 5.1.46

OS: Ubuntu 10.04

 

Será que você tem alguma idéia do que pode estar acontecendo ? =x

 

Desde já,

Obrigado

Compartilhar este post


Link para o post
Compartilhar em outros sites

poste como ficou o teu script atual.

 

e se possível as estruturas das tabelas, se constatarmos que o problema é na realização das consultas, movo para o fórum do teu DB.

 

para isso, vamos trocar os mysql_query.., por apenas: echo ...

assim o processamento do script não vai depender do banco. Se continuar lento, o problema está no código php. Caso contrário, vamos ver melhor o banco.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O problema é o número de consultas que você executa.

Você disse $_online retorna 150 registros e $q_sproof mais 120. Ou seja, são no mínimo 270 querys enviadas ao MySQL, e isso compromete muito o seu script.

 

Leia esse artigo que ele irá lhe ajudar muito: http://blog.thiagobelem.net/mysql/cadastrando-multiplos-registros-no-mysql-ao-mesmo-tempo/

Compartilhar este post


Link para o post
Compartilhar em outros sites

Nossa, BRIGADÃO André. Genial essa forma de fazer =P

 

Dei uma modificada no sistema, pra enchugar ainda mais o que não precisava e utilizei o esquema do blog que o André passou, ficando assim:

 

<?PHP
$world_id = 0;
$world_name = $config['server']['serverName'];

$order = $_REQUEST['order'];

$orderby = ( !empty($order) ) ? $order : 'name';

$SQL->query("UPDATE players SET online = '0', spoof = '0' WHERE spoof = '1'");
//$q_online = mysql_query("SELECT DISTINCT * FROM players WHERE world_id = '".(int) $world_id."' AND online = 1", $cn) or die(mysql_error());
//$pon = mysql_fetch_object($q_online);
$q_online = $SQL->query("SELECT id, account_id, name, level, vocation, promotion FROM players WHERE online = 1 GROUP BY account_id");
$i = 0;
$table = '';
foreach($q_online as $player){
if(is_int($i / 2)){
	$bgcolor = $config['site']['darkborder'];
	}else{
	$bgcolor = $config['site']['lightborder'];
	}
	$table .= '<TR BGCOLOR='.$bgcolor.'><TD WIDTH=70%><A HREF="?subtopic=characters&name='.urlencode($player['name']).'">'.$player['name'].$rs.'</A></TD><TD WIDTH=10%>'.$player['level'].'</TD><TD WIDTH=20%>'.$vocation_name[$world_id][$player['promotion']][$player['vocation']].'</TD></TR>';
		$i++;
}

$limit_spoof = ($config['status']['serverStatus_players'] - $i);

$q_spoof = $SQL->query("SELECT * FROM players WHERE online = 0 AND level > 8 and group_id < 2 GROUP BY account_id LIMIT ".$limit_spoof."");
$sql = "UPDATE players SET online = '1', spoof = '1' WHERE";	
foreach($q_spoof as $spoof){
	if(is_int($i / 2)){
	$bgcolor = $config['site']['darkborder'];
	}else{
	$bgcolor = $config['site']['lightborder'];
	}
		 	$table .= '<TR BGCOLOR='.$bgcolor.'><TD WIDTH=70%><A HREF="?subtopic=characters&name='.urlencode($spoof['name']).'">'.$spoof['name'].$rs.'</a></TD><TD WIDTH=10%>'.$spoof['level'].'</TD><TD WIDTH=20%>'.$vocation_name[$world_id][$spoof['promotion']][$spoof['vocation']].'</TD></TR>';
		 	//$SQL->query("UPDATE players SET online = '1', spoof = '1' WHERE id = '".$spoof['id']."'");
		 	$sql .= " id = '{$spoof['id']}' OR";
			 	$i++;
}
$sql = substr($sql, 0, -2);

$number_of_players_online = 0;
$kills = 6;
$time = 3 * 60 * 60 * 1000;
$hasRs = $kills * $time;
$rs = "";


if ($player['skulltime'] > 0 && $player['skull'] == 0)
	$rs = "<img style='border: 0;' src='./images/whiteskull.gif'/>";
else if ($player['skulltime'] >= $hasRs or $player['skull'] == 1)
	$rs = "<img style='border: 0;' src='./images/redskull.gif'/>";

if($i == 0)
//server status - server empty
$main_content .= '<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=4 WIDTH=100%><TR BGCOLOR="'.$config['site']['vdarkborder'].'"><TD CLASS=white><B>Server Status</B></TD></TR><TR BGCOLOR='.$config['site']['darkborder'].'><TD><TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1><TR><TD>Currently no one is playing on <b>'.$config['site']['worlds'][$world_id].'</b>.</TD></TR></TABLE></TD></TR></TABLE><BR>';
else
{

//server status - someone is online
$main_content .= '<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=4 WIDTH=100%><TR BGCOLOR="'.$config['site']['vdarkborder'].'"><TD CLASS=white><B>Server Status</B></TD></TR><TR BGCOLOR='.$config['site']['darkborder'].'><TD><TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1><TR><TD>Currently '.$i.' players are online on <b>'.$config['site']['worlds'][$world_id].'</b>.</TD></TR></TABLE></TD></TR></TABLE><BR>';


$main_content .= "<table width='100%' cellspacing='1'>
	<tr>
		<td style='background: ".$bgcolor.";' align='center'>
			<img src='./images/whiteskull.gif'/> - 1 - 6 Frags
			<br/>
			<img src='./images/redskull.gif'/> - 6+ Frags or Red Skull
		</td>
	</tr>
	</table>";

//list of players
$main_content .= '<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=4 WIDTH=100%><TR BGCOLOR="'.$config['site']['vdarkborder'].'"><TD><A HREF="?subtopic=whoisonline&order=name" CLASS=white>Name</A></TD><TD><A HREF="?subtopic=whoisonline&order=level" CLASS=white>Level</A></TD><TD><A HREF="?subtopic=whoisonline&order=vocation" CLASS=white>Vocation</TD></TR>'.$table.'</TABLE>';
//search bar
$main_content .= '<BR><FORM ACTION="?subtopic=characters" METHOD=post>  <TABLE WIDTH=100% BORDER=0 CELLSPACING=1 CELLPADDING=4><TR><TD BGCOLOR="'.$config['site']['vdarkborder'].'" CLASS=white><B>Search Character</B></TD></TR><TR><TD BGCOLOR="'.$config['site']['darkborder'].'"><TABLE BORDER=0 CELLPADDING=1><TR><TD>Name:</TD><TD><INPUT NAME="name" VALUE=""SIZE=29 MAXLENGTH=29></TD><TD><INPUT TYPE=image NAME="Submit" SRC="'.$layout_name.'/images/buttons/sbutton_submit.gif" BORDER=0 WIDTH=120 HEIGHT=18></TD></TR></TABLE></TD></TR></TABLE></FORM>';
}
?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

neste caso precisar de um update para cada condição WHERE, se fosse a mesma poderia atualizar vários campos mas como não é

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.