Server krasjer ved bruk av $i++

tyr897

Medlem
Har du mer data i databasen på serveren? Kanskje du har dårlig satt opp indekser og spørringen tar for lang tid.

edit: Ser du fant ut det samme selv :)
Kjør EXPLAIN på spørringen og post en dump av tabellstrukturen din med indekser.
 

clinton4

Medlem
Nå sitter jeg på en iphone, så jeg ser ikke hele koden din.

Ser du skriver $i++, har du husket å lukke denne med ; på slutten?
 

Walgermo

New Member
Aldri testet EXPLAIN før, men slik ble det om jeg har gjort det rett.

PHP:
Viser rader 0 - 3 (4 totalt, Spørring tok 0.0058 sek)
EXPLAIN (
SELECT date, user_country, training.user_id, users.user_id AS uu, kg, rep, training.training_id, lifts.training_id AS lt, bodyweight
FROM lifts, training, users
WHERE kg = ( 
SELECT max( kg ) 
FROM lifts
WHERE rep =2
AND exercise_id =5
AND training.training_id = lifts.training_id
AND training.user_id = users.user_id ) 
GROUP BY user_id
ORDER BY ABS( kg ) DESC , ABS( bodyweight ) ASC , ABS( date ) ASC 
LIMIT 5 
)


id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra 
1	PRIMARY	users	ALL	NULL	NULL	NULL	NULL	4	Using temporary; Using filesort
1	PRIMARY	training	ALL	NULL	NULL	NULL	NULL	23	 
1	PRIMARY	lifts	ALL	NULL	NULL	NULL	NULL	739	Using where
2	DEPENDENT SUBQUERY	lifts	ALL	NULL	NULL	NULL	NULL	739	Using where

Hvordan dumper jeg på den måten du sa? :p slik?

PHP:
-- phpMyAdmin SQL Dump
-- version 3.3.8
-- http://www.phpmyadmin.net
--
-- Vert: localhost
-- Generert den: 04. Feb, 2011 09:54 AM
-- Tjenerversjon: 5.0.87
-- PHP-Versjon: 5.2.9

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `walgermo_workoutplace`
--

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

--
-- Tabellstruktur for tabell `country`
--

CREATE TABLE IF NOT EXISTS `country` (
  `country_id` tinyint(4) NOT NULL auto_increment,
  `country_iso` varchar(30) character set utf8 collate utf8_bin NOT NULL,
  `country_name` varchar(100) character set utf8 collate utf8_bin NOT NULL,
  PRIMARY KEY  (`country_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

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

--
-- Tabellstruktur for tabell `exercise_category`
--

CREATE TABLE IF NOT EXISTS `exercise_category` (
  `ex_cat_id` mediumint(8) unsigned NOT NULL auto_increment,
  `ex_cat_name` varchar(100) character set utf8 collate utf8_bin NOT NULL,
  PRIMARY KEY  (`ex_cat_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=17 ;

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

--
-- Tabellstruktur for tabell `exercise_name`
--

CREATE TABLE IF NOT EXISTS `exercise_name` (
  `ex_id` mediumint(8) NOT NULL auto_increment,
  `ex_cat_id` mediumint(8) NOT NULL,
  `ex_name` varchar(100) character set utf8 collate utf8_bin NOT NULL,
  PRIMARY KEY  (`ex_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=125 ;

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

--
-- Tabellstruktur for tabell `lifts`
--

CREATE TABLE IF NOT EXISTS `lifts` (
  `training_id` int(10) NOT NULL,
  `set_id` int(20) NOT NULL auto_increment,
  `kg` decimal(6,2) NOT NULL,
  `rep` int(20) NOT NULL,
  `exercise_id` mediumint(8) NOT NULL,
  PRIMARY KEY  (`set_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1719 ;

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

--
-- Tabellstruktur for tabell `training`
--

CREATE TABLE IF NOT EXISTS `training` (
  `training_id` int(20) NOT NULL auto_increment,
  `user_id` mediumint(8) NOT NULL,
  `title` varchar(250) character set utf8 collate utf8_bin NOT NULL,
  `date` int(11) NOT NULL,
  `comment` longtext character set utf8 collate utf8_bin NOT NULL,
  `bodyweight` decimal(5,2) NOT NULL,
  `timespent_hours` int(3) NOT NULL,
  `timespent_minutes` int(3) NOT NULL,
  `disable_comment` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`training_id`),
  UNIQUE KEY `training_id` (`training_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=77 ;

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

--
-- Tabellstruktur for tabell `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` mediumint(8) unsigned NOT NULL auto_increment,
  `user_rank` tinyint(2) unsigned NOT NULL default '1',
  `user_email` varchar(100) collate utf8_bin NOT NULL,
  `user_password` varchar(40) collate utf8_bin NOT NULL,
  `user_birthday` varchar(10) collate utf8_bin NOT NULL,
  `user_lang` varchar(30) collate utf8_bin NOT NULL default 'en',
  `user_country` varchar(10) collate utf8_bin NOT NULL,
  `user_firstname` varchar(100) collate utf8_bin NOT NULL,
  `user_lastname` varchar(100) collate utf8_bin NOT NULL,
  `user_gender` varchar(10) collate utf8_bin NOT NULL,
  `user_dateformat` varchar(100) collate utf8_bin NOT NULL default 'd.m.Y',
  `user_dateformat_long` varchar(100) collate utf8_bin NOT NULL default 'd.m.Y @ H:i:s',
  `user_timezone` decimal(5,2) NOT NULL default '0.00',
  `user_joined` int(11) unsigned NOT NULL,
  `user_lastlogin` int(11) unsigned default '0',
  `user_posts` mediumint(8) NOT NULL default '0',
  `user_status` varchar(100) collate utf8_bin default NULL,
  `user_bodyweight` decimal(5,2) NOT NULL,
  `user_weight_metric` varchar(3) collate utf8_bin NOT NULL default 'kg',
  `user_activationKey` varchar(40) collate utf8_bin default NULL,
  `user_avatarPath` varchar(100) collate utf8_bin default NULL,
  `user_blog_privacy` tinyint(1) NOT NULL default '0',
  `user_blogs_per_page` tinyint(3) NOT NULL default '5',
  `user_msg_from_comments` tinyint(1) unsigned NOT NULL default '1',
  `user_show_blog_comments` tinyint(1) unsigned NOT NULL default '1',
  PRIMARY KEY  (`user_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=21 ;
 
Sist redigert:

Walgermo

New Member
Det fungerer egentlig, men det tar ca.30 sekunder.. er det fordi i nyere versjon av mysql så er spørringer satt opp på denne måten optimalisert?
 

Nutz

Med lem
Når du får ting opp å gå, så må/bør du gjøre noe med sikkerheten.
Kjøre Post-variabler rett inn i spørring uten sanering er FY-FY.
 

amaheath

Medlem
Hallo, ville trodd du trengte en where til - for å joine de 3 tabellene?

Nå joiner du training, lifts og users inne i (where exists..... ) men ikke i selve hovedqueriet.

Så da leser databasen alle lifts * alle users * alle training, og sjekker så den subquerien. Det vil ta vanvittig lang tid. :)

Hiv på


AND training.training_id = lifts.training_id
AND training.user_id = users.user_id

rett før GROUP BY og se om det hjelper...
 

Walgermo

New Member
Hallo, ville trodd du trengte en where til - for å joine de 3 tabellene?

Nå joiner du training, lifts og users inne i (where exists..... ) men ikke i selve hovedqueriet.

Så da leser databasen alle lifts * alle users * alle training, og sjekker så den subquerien. Det vil ta vanvittig lang tid. :)

Hiv på


AND training.training_id = lifts.training_id
AND training.user_id = users.user_id

rett før GROUP BY og se om det hjelper...
Lol, ca 1001% raskere spørring :p hehe.. ser du noe andre måter å optimalisere på da? hehe.. er ganske så fersk mtp programmering så ikke alt som er på plass ennå tydeligvis.

Takk for rettingen! :)
 

tyr897

Medlem
Dette har lite med MySQL versjon å gjøre, det handler om spørring, tabellstruktur og menger data.

I forklaringen av spørringen ser du at MySQL må benytte seg av "Using temporary; Using filesort". Dette er ikke bra. Midlertidig tabell og sortering på filsystemet går alltid tregt, og vil bli verre jo større databasen din blir. I en webapplikasjon må du rett og slett unngå det. Som regel går dette greit med skikkelige indekser, og iblant en restrukturering av spørringen.

Spørringen din er litt forvirrende, anbefaler at du slenger på tabellnavn eller alias på alle feltene slik at det er åpenbart hvilket felt som hører til hvor uten å måtte konsultere tabelldefinisjonene dine. Hvis du også forandrer fra theta joins til vanlige for lesbarhet, kan jeg hjelpe deg litt ytterliggere på vei. En grei forklaring finnes her.

I ditt tilfelle har du har ikke satt noen indekser utenom primærnøkler. Start med å lage en indeks på alle fremmednøkler.

Helt umiddelbart seg jeg at du trenger indeks på training.user_id og lifts.training_id, samt lifts.excercise_id og lifts.rep siden du gjør et oppslag mot de.
 

Walgermo

New Member
Okej :)

Testet EXPLAIN på nytt nå..

PHP:
Kommandoen/spørringen er utført
EXPLAIN (
SELECT 
training.date, 
user_country, 
training.user_id, 
users.user_id AS uu, 
lifts.kg, 
lifts.rep, 
training.training_id, 
lifts.training_id AS lt, 
training.bodyweight
FROM lifts, training, users
WHERE kg = ( 
SELECT max( kg ) 
FROM lifts
WHERE rep =2
AND exercise_id =5
AND training.training_id = lifts.training_id
AND training.user_id = users.user_id )
AND training.training_id = lifts.training_id 
AND training.user_id = users.user_id 
GROUP BY user_id
ORDER BY ABS( kg ) DESC , ABS( bodyweight ) ASC , ABS( date ) ASC 
LIMIT 5 
)

id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra 
1	PRIMARY	users	ALL	PRIMARY	NULL	NULL	NULL	5	Using temporary; Using filesort
1	PRIMARY	training	ref	PRIMARY,user_id	user_id	3	walgermo_workoutplace.users.user_id	3	Using where
1	PRIMARY	lifts	ref	training_id	training_id	4	walgermo_workoutplace.training.training_id	31	Using where
2	DEPENDENT SUBQUERY	lifts	ref	training_id,exercise_id,rep	exercise_id	3	const	7	Using where
 
Sist redigert:

Sjefskoder

Sjefskoder
Få se HELE php koden din..

/Sjef
 

Walgermo

New Member
Her har du hele smørja..

PHP:
<!-- login START -->
                <?php
				if( !checkSession() )
				{
					include('page/login.php');
					exit;
				} 
				include('inc/functions_blog.php');
				$dateformat = $CONFIG['date_format'];
				?>
<!-- login END -->

<div id='postpath'>
		<a title="<?php echo translate('gotofrontpage'); ?>" href="index.php"><?php echo translate('home'); ?></a>
		 &gt; <a href="index.php?action=home&sub=hof" title='<?php echo translate('hof'); ?>'><?php echo translate('hof'); ?></a>
</div>
<h1><?php echo translate('hof'); ?></h1>
<br />
<?php 	echo translate('hofdescription'); ?>
<br />
<br />
<form method="post" action="index.php?action=home&sub=hof"> 

	<table border="0">
    <tr>
    <td>
	<b><?php echo ucf(translate('exercise')); ?>:</b>
    </td>
    <td>
	<select name="select_exercise">
    <?php
	$sql= mysql_query("SELECT * FROM exercise_name ORDER BY ex_name ASC");
	while($row = mysql_fetch_assoc($sql))
	{	
		$ex_id = $row['ex_id'];
		$ex_name = $row['ex_name'];	
        echo '<option name="ex_id" value='. $ex_id.'>'. translate($ex_name) . '</option>';
    }
    ?>
    </td>
	</select>
  
    	<td align="right">
        <b><?php echo ucf(translate('gender')); ?>:</b>
        </td>
        
        <td>
        <select name="gender">
        <option name="gender" value=""><?php echo ucfirst(translate('both')); ?></option>
		<option name="gender" value="male"><?php echo ucf(translate('male')); ?></option>
        <option name="gender" value="female"><?php echo ucf(translate('female')); ?></option>		
        </select>    
        </td>
    
 
    
        <td align="right">
        <b><?php echo ucf(translate('reps')); ?>:</b>
        </td>
        
        <td>
        <select name="reps">
        <option name="reps" value="1" selected="selected">1RM</option>
        <option name="reps" value="2">2RM</option>
        <option name="reps" value="3">3RM</option>
        <option name="reps" value="4">4RM</option>
        <option name="reps" value="5">5RM</option>
        <option name="reps" value="6">6RM</option>
        <option name="reps" value="7">7RM</option>
        <option name="reps" value="8">8RM</option>
        <option name="reps" value="9">9RM</option>
        <option name="reps" value="10">10RM</option>
        </select>
        </td>
  
    
        <td align="right">
        <b><?php echo ucf(translate('top')); ?>:</b>
        </td>
        
        <td>
        <select name="nr_to_show">
        <option name="nr_to_show" value="10" selected="selected">10</option>
        <option name="nr_to_show" value="20">20</option>
        <option name="nr_to_show" value="30">30</option>
        <option name="nr_to_show" value="40">40</option>
        <option name="nr_to_show" value="50">50</option>
        <option name="nr_to_show" value="60">60</option>
        <option name="nr_to_show" value="70">70</option>
        <option name="nr_to_show" value="80">80</option>
        <option name="nr_to_show" value="90">90</option>
        <option name="nr_to_show" value="100">100</option>
        </select>
        </td>
    
        <td>
        <input type="submit" style="font-weight:bold;" name="select" value=" <?php echo ucf(translate('show')); ?> "  />
        </td>
    </table>
</form>

<?php 
if(isset($_POST['select']))
{
	$ex_id = $_POST['select_exercise'];
	$gender = $_POST['gender'];
	$nr_reps = $_POST['reps'];
	$nr_to_show = $_POST['nr_to_show'];

echo "<br /><h1>" . ucf(translate(getExercisename($ex_id))) . " - ". $nr_reps . "RM - ". translate('top') ." " . $nr_to_show ."</h1><br />";
	
	
if($gender == "")
{
	// Get all the data
	$result = mysql_query("SELECT 
	training.date, 
	user_country, 
	training.user_id, 
	users.user_id AS uu, 
	lifts.kg, 
	lifts.rep, 
	training.training_id, 
	lifts.training_id AS lt, 
	training.bodyweight 
	FROM lifts, training, users 
	WHERE kg=(SELECT max(kg) FROM lifts WHERE rep= ". $nr_reps ." AND exercise_id = ". $ex_id ." AND training.training_id = lifts.training_id AND training.user_id = users.user_id)
	AND training.training_id = lifts.training_id 
	AND training.user_id = users.user_id 
	GROUP BY user_id
	ORDER BY ABS(kg) DESC, ABS(bodyweight) ASC, ABS(date) ASC 
	LIMIT ". $nr_to_show ." ") or die(mysql_error()); 
}
else
{
	// Get all the data with sex seleceted
	$result = mysql_query("SELECT 
	training.date, 
	user_country, 
	training.user_id, 
	users.user_id AS uu, 
	lifts.kg, 
	lifts.rep, 
	training.training_id, 
	lifts.training_id AS lt, 
	training.bodyweight 
	FROM lifts, training, users 
	WHERE kg=(SELECT max(kg) FROM lifts WHERE rep= ". $nr_reps ." AND exercise_id = ". $ex_id ." AND training.training_id = lifts.training_id AND training.user_id = users.user_id AND user_gender='". $gender ."') 
	AND training.training_id = lifts.training_id 
	AND training.user_id = users.user_id
	GROUP BY user_id
	ORDER BY ABS(kg) DESC, ABS(bodyweight) ASC, ABS(date) ASC 
	LIMIT ". $nr_to_show ." ") or die(mysql_error()); 
}
$num = mysql_num_rows($result);
$i=1;
if($i <= $num)
{ 
		echo "<table border='1' width='100%'>";
		echo "<tr><th>#</th><th>" . ucf(translate('country')) . "</th><th>" . ucf(translate('navn')) . "</th><th>" . translate('date') . "</th><th>" . ucf(translate('bodyweight')) . "</th><th>". translate('lifted') ."</th></tr>";
		
		// keeps getting the next row until there are no more to get
		while($row = mysql_fetch_array( $result )) 
		{
			// Print out the contents of each row into a table
			echo "<tr><td align='center'>";
			if($i == 1): echo "<img src='img/gold.png' />"; endif;
			if($i == 2): echo "<img src='img/silver.png' />"; endif; 
			if($i == 3): echo "<img src='img/bronze.png' />"; endif; 
			echo $i++;
			echo "</td><td align='center'>";
			echo "<div><img src='img/flags/16/". strtolower($row['user_country']) .".png' /></div> " . translate(ucf(getCountryName(strtolower($row['user_country'])))) . "";
			echo "</td><td align='center'>";
			echo "<a href='index.php?action=profile&sub=show&tid=". $row['training_id'] ."'>" . getNameFromId($row['user_id']) . "</a>"; 
			echo "</td><td align='center'>";
			echo formatDate($row['date'], $dateformat);
			echo "</td><td align='center'>";
			echo r_nr2(calcFromKg($row['bodyweight'])). $w_metric;
			echo "</td><td align='center'>"; 
			echo r_nr(calcFromKg($row['kg'])). $w_metric;
			echo "</td></tr>"; 
		}
		
		echo "</table>
		<div class='fixed'>
							</div>
						</div>
						</div>
					<div class='fixed'>
					</div>
					<div id='footer'>
					<a id='gotop' href='#' onclick='MGJS.goTop();return false;'>" . translate('top') . "</a>
						<div align='center' id='copyright'>&copy; " . translate('copyrightyear') . " " . translate('header_text'). " - " .  translate('curversion') ." - <a href='index.php?action=contact'>" . translate('contact') ."</a> - <a href='index.php?action=about'>" . translate('about') . "</a> - " . translate('onlineusers'). ": " . getActiveUsers() . "<br />
						</div>";
			exit;
			
}
else
{
	echo translate('noresultshof');
	echo "<div class='fixed'>
					</div>
				</div>
				</div>
			<div class='fixed'>
			</div>
			<div id='footer'>
			<a id='gotop' href='#' onclick='MGJS.goTop();return false;'>" . translate('top') . "</a>
				<div align='center' id='copyright'>&copy; " . translate('copyrightyear') . " " . translate('header_text'). " - " .  translate('curversion') ." - <a href='index.php?action=contact'>" . translate('contact') ."</a> - <a href='index.php?action=about'>" . translate('about') . "</a> - " . translate('onlineusers'). ": " . getActiveUsers() . "<br />
                </div>";
	exit;
} 
}
?>
 

Pong

Jeg selger sʇɥƃıluʍop :)
</td>
</select>
som avslutter excercise-td'n har feil rekkefølge.

Men jeg lurer på hvordan du har modellert dataene. Men husker jeg rett er dette en lett sak for RipZ å forstå seg på uten noe videre dokumentaspjon...
 

Walgermo

New Member
</td>
</select>
som avslutter excercise-td'n har feil rekkefølge.

Men jeg lurer på hvordan du har modellert dataene. Men husker jeg rett er dette en lett sak for RipZ å forstå seg på uten noe videre dokumentaspjon...
Ahh, stemmer.. ;)

Hva mener du med modellert? :rolleyes: hehe, alt er selvlært så har ikke så mye erfaring/peiling på alle faguttrykkene.. lett sak for RipZ ? :)

Altså det fungere greit nå, men som tyr897 påpeker:
I forklaringen av spørringen ser du at MySQL må benytte seg av "Using temporary; Using filesort". Dette er ikke bra. Midlertidig tabell og sortering på filsystemet går alltid tregt, og vil bli verre jo større databasen din blir. I en webapplikasjon må du rett og slett unngå det. Som regel går dette greit med skikkelige indekser, og iblant en restrukturering av spørringen.
 
Topp