Page 1 sur 1

Refaire cette requete plus rapidement (mysql)

Posté : 23 mai 2008, 02:06
par Baboo
Bonjour j'ai dans une page index plusieurs include, hors un de c'est include comporte des requetes dans ma base de donnée et cela fait que ma page s'affiche apres 5 secondes ce qui est enorme.

Le bout en question est dans une boucle foreach

			$con = mysql_connect('localhost','Video','video');
			$UpdateSql = "UPDATE Video SET  `VideoId` = '$id', `Title` = '$title', `VideoUrl` = '$rurl', `Channel` = '$type', `ChannelUrl` = '$typeurl', `DateFound` = '$datefound', `Description` = '$description', `Actor` = '$actor', `Director` = '$director', `Writer` = '$writer', `Producer` = '$producer', `Artist` = '$artist', `Album` = '$album', `Author` = '$author', `Rating` = '$rating', `Runtime` = '$runtime', `Category` = '$category', `Tags` = '$tags', `ShowName` = '$showname', `ShowUrl` ='$showurl', `EpisodeName` = '$episodename', `EpisodeNumber` = '$episodenumber, `SeasonNumber` = '$seasonnumber, `Country` = '$country', `Language` = '$language', `DateProduced` = '$dateproduced', `ViewCount` = '$viewcount', `UserRating` = '$userrating', `UserRatingCount` = '$userratingcount', `VideoEmbed` = '$link', `Quality` = '$quality', `Filesize` = '$size', `Adult` = '$adult' WHERE `Channel` = '$type' AND `Title`= '$title' ";
			

			$InsertSql = "INSERT INTO `Video` (`Id`, `VideoId`, `Title`, `VideoUrl`, `Channel`, `ChannelUrl`, `DateFound`, `Description`, `Actor`, `Director`, `Writer`, `Producer`, `Artist`, `Album`, `Author`, `Rating`, `Runtime`, `Category`, `Tags`, `ShowName`, `ShowUrl`, `EpisodeName`, `EpisodeNumber`, `SeasonNumber`, `Country`, `Language`, `DateProduced`, `ViewCount`, `UserRating`, `UserRatingCount`, `VideoEmbed`, `Quality`, `Filesize`, `Adult`) VALUES (NULL, '$id', '$title', '$rurl', '$type', '$typeurl', '$datefound', '$description2', '$actor', '$director', '$writer', '$producer', '$artist', '$album', '$author', '$rating', '$runtime', '$category', '$tags', '$showname', '$showurl', '$episodename', '$episodenumber', '$seasonnumber', '$country', '$language', '$dateproduced', '$view', '$userrating', '$userratingcount', '$link', '$quality', '$size', '$adult');";

			if (!$con)
            {
            die('Could not connect: ' . mysql_error());
            }
			
            mysql_select_db("Video", $con);
			
            $query = "SELECT Id FROM Video WHERE title='$title' AND channel= '$type'";
            $result = mysql_query($query);
            		
			if (!mysql_fetch_row($result)) {
            //noting so we need to add it
			mysql_query($InsertSql);
			$InsertId = mysql_insert_id();
			}
			else
			{
			mysql_query($UpdateSql);
		    $result = mysql_query($query);
	        $row = mysql_fetch_row($result);
		    $InsertId = $row[0];
            	
            }


			
            mysql_close($con);


Pour chaque enregistrement je verifie si l'info est dans la base sinon je l'ajoute si l'info est la je la met a jour.

Pour l'instant ma base contient 100 000 enregistrement mais vous pouvez compter 10 000 de plus chaque jour.

Donc avez vous une suggestion pour amélioré grandement ce code ?
Pui-je faire en sorte d'afficher ma page et ensuite entrer les info dans la base de donnée ?

Merci d'avance

Posté : 23 mai 2008, 05:03
par Patriboom
Il n'y a pas de foreach dans le code que tu présentes ci-haut.

Ta table a-t-elle un index? Si non, tu pourrais lui faire un index sur plusieurs champs et donner la propriété "Unique" à cet index. Il te suffirait alors de faire un "Insert" systématique avec toutes les données soumises. Sur message d'erreur, alors tu pourrais faire appel à ta fonction "Update" Ainsi, tu sauverais l'étape de lecture/vérification des existantes.

Posté : 23 mai 2008, 07:47
par @rthur
Bonjour,

Au lieu de faire un SELECT puis INSERT ou UPDATE, n'est-il pas possible d'utiliser la commande "tout-en-un" REPLACE:
http://dev.mysql.com/doc/refman/5.0/fr/replace.html

:)

Posté : 23 mai 2008, 11:06
par Ryle
Il n'y a pas de foreach dans le code que tu présentes ci-haut.
D'après ce qu'il dit, tout le code ci-dessus se trouve dans le foreach ;)

Tu pourrais d'ailleurs gagner beaucoup en ouvrant la connexion une fois pour toute (et en sélectionnant la base) en dehors de la boucle plutôt que de la ré-ouvrir à chaque itération (et mettre le close en dehors).

Maintenant un index sur les champs title et channel te permettrait d'aller plus vite pour le select, mais ralentirait l'update/insert.
Pour gagner du temps sur l'update, lorsque tu as testé si l'enregistrement existant, tu en récupère l'identifiant (clé primaire).
Plutôt que repasser les deux infos title et channel dans la condition de l'update utilise la clé primaire il ira beaucoup plus vite à trouver l'enregistrement concerné.
Si tu n'utilise pas le $InsertId dans ta boucle, alors ne fait pas inutilement appel à mysql_insert_id() ou mysql_fetch_row($result) :)

Posté : 23 mai 2008, 19:26
par Patriboom
Bonjour,

Au lieu de faire un SELECT puis INSERT ou UPDATE, n'est-il pas possible d'utiliser la commande "tout-en-un" REPLACE:
http://dev.mysql.com/doc/refman/5.0/fr/replace.html

:)
Merci, ça me servira aussi. Je n'avais jamais vu la fonction REPLACE.
Elle est le meilleur choix, c'est certain.

Posté : 23 mai 2008, 22:48
par Invité
Merci a vous tous pour vos reponse je vais testé pour voir ce qui me sauveras du temps precieux.

Mais j'y pense existe t-il un moyen de faire un update et de s'avoir si il y a eu bel et bien un update ?

Donc je pourais faire

if(update==true){
//rien}
else{
//inserer car n'existe pas
}

Cela ne sauvrais t-il pas du temps ?
(je suis pas fort coté mysql)

Merci encore a tous

Posté : 23 mai 2008, 23:00
par zeus
Cette logique est bien car le pourcentage de mise à jour est beaucoup plus important que le nombre d'insertion. Partons sur un 80%/20%

Donc, dans 80% du temps, tu auras une seule requête, et dans les 20% restants, 2 requêtes.
Alors que le REPLACE exécute tout le temps 2 requêtes. Après, le REPLACE fait tout en interne, donc 2 requêtes dans le REPLACE seront plus rapides que 2 requêtes exécutées en PHP, mais je pense que la différence est négigable et que ta solution reste celle qui exécute le moins de requête ;)

Posté : 24 mai 2008, 00:08
par Invité
En fait je dirais que sur mon site le ration insert/update serais plutot de 70%/30%

Mais une question sur le Replace : va t"il changer le numero d'id ? (qui lui est a auto increment)

Car si mon enregistrement par exemple 54 555 devient 200 545 je me retrouve avec une page vide pour les internaute qui eux aurais comme lien 54 555 ....

Posté : 24 mai 2008, 00:32
par Invité
Voila la solution du probleme :
$query = "SELECT Id FROM Video WHERE title='$title' AND channel= '$type'"; 
Changer pour :
$query = "SELECT Id FROM Video WHERE title='$title' AND channel= '$type' LIMIT=1"; 
Moi comme pauvre con je lui faisait lire mes 100 000 enregistrements meme si il en avait déja trouvé une !

Je vient de passer d'un temps moyen de chargement de 6 secondes a 0.200 secondes !
Je vais tout de même approfondir mes connaisance avec ce message.

Merci encore a tous

Posté : 24 mai 2008, 06:38
par Patriboom
Pour voir s'il y eut update ou non dans ton formulaire, tu peux mettre une case à cocher non-sélectionnée à tous les items. Aux items qui seront modifiés, tu feras (javascript ou ajax) mettre un crochet dans la case. Ensuite, lors de la soumission du formulaire, tu n'auras qu'à traiter les lignes où la case "update" est sélectionnée.

Posté : 25 mai 2008, 10:53
par Ryle
Mais j'y pense existe t-il un moyen de faire un update et de s'avoir si il y a eu bel et bien un update ?
mysql_affected_rows() retourne le nombre de lignes affectées lors de la dernière requête INSERT, UPDATE, REPLACE ou DELETE :)