Dotclear

Vous n'êtes pas identifié(e).

Annonce

#1 2011-12-16 10:27:05

adjaya
Membre
Lieu : Provence - Luberon
Inscription : 2006-09-05
Site Web

Plugin Tag - Function setTags($cur,$pos_id)- optimisation

Bonjour
je me suis amusé à suivre le parcours de la function setTags() et voila ce qu'il en ressort :

//			$meta->delPostMeta($post_id,'tag');
			$strReq = 'DELETE FROM '.$this->table.' '. //table meta
					'WHERE post_id = '.$post_id;
			if ($type !== null) {
				$strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
			}
			if ($meta_id !== null) {
				$strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' ";
			}
			$this->con->execute($strReq); #
	//		$this->updatePostMeta((integer) $post_id);
			$post_id = (integer) $post_id;
			
			$strReq = 'SELECT meta_id, meta_type '.
					'FROM '.$this->table.' '.
					'WHERE post_id = '.$post_id.' ';
			$rs = $this->con->select($strReq); #
			$meta = array();
			while ($rs->fetch()) {
				$meta[$rs->meta_type][] = $rs->meta_id;
			}
			$post_meta = serialize($meta);
			$cur = $this->con->openCursor($this->core->prefix.'post');
			$cur->post_meta = $post_meta;
			$cur->update('WHERE post_id = '.$post_id); #
			$this->core->blog->triggerBlog();

			
			foreach ($meta->splitMetaValues($tags) as $tag) {
				//$meta->setPostMeta($post_id,'tag',$tag);
				$this->checkPermissionsOnPost($post_id);
				$value = trim($value);
				if ($value === false) { return; }
				$cur = $this->con->openCursor($this->table); //table meta
				$cur->post_id = (integer) $post_id;
				$cur->meta_id = (string) $value;
				$cur->meta_type = (string) $type;
				$cur->insert(); #
				
				//$this->updatePostMeta((integer) $post_id);
				$post_id = (integer) $post_id;
				$strReq = 'SELECT meta_id, meta_type '.
						'FROM '.$this->table.' '.
						'WHERE post_id = '.$post_id.' ';
				$rs = $this->con->select($strReq); #
				$meta = array();
				while ($rs->fetch()) {
					$meta[$rs->meta_type][] = $rs->meta_id;
				}
				$post_meta = serialize($meta);
				$cur = $this->con->openCursor($this->core->prefix.'post');
				$cur->post_meta = $post_meta;
				$cur->update('WHERE post_id = '.$post_id); #
				$this->core->blog->triggerBlog();
			}

Je mettrais ma main à couper qu'il y a là matière à optimisation.
Je suis en train de voir ce que donnerais une méthode setMetas() qui factoriserais le code du parcours ci-dessus.

Dernière modification par adjaya (2011-12-16 10:29:23)


Photo, Art et Création Numérique : http://benoit-grelier.photo7.fr/

Hors ligne

#2 2011-12-16 14:52:07

adjaya
Membre
Lieu : Provence - Luberon
Inscription : 2006-09-05
Site Web

Re : Plugin Tag - Function setTags($cur,$pos_id)- optimisation

Un premier jet

	public static function setTags($cur,$post_id)
	{
		$post_id = (integer) $post_id;
		
		if (isset($_POST['post_tags'])) {
			$tags = $_POST['post_tags'];
			$meta =& $GLOBALS['core']->meta;
			
			$meta->setMetas($post_id,$tags,'tag');
	}
	
	public function setMetas($post_id,$metas,$type=null)
	{
		$this->checkPermissionsOnPost($post_id);

		$strReq = 'DELETE FROM '.$this->table.' '.
				'WHERE post_id = '.$post_id;
		if ($type !== null) {
			$strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
		}
		if ($meta_id !== null) {
			$strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' ";
		}
		$this->con->execute($strReq); #

		$meta=array();
		foreach ($this->splitMetaValues($tags) as $value)
		{
			$value = trim($value);
			if ($value === false) { continue; }
			$cur = $this->con->openCursor($this->table);
			$cur->meta_id = (string) $value;
			$cur->post_id = (integer) $post_id;	
			$cur->meta_type = (string) $type;		
			$cur->insert(); #
				
			$meta[$type][] = $value;		
		}

		$post_meta = serialize($meta);
		$cur = $this->con->openCursor($this->core->prefix.'post');
		$cur->post_meta = $post_meta;
		$cur->update('WHERE post_id = '.$post_id); #
		$this->core->blog->triggerBlog(); #
	}

Pour donner une idée, avec la méthode actuelle, pour 10 tag sur un billet on fait:
2 + ( 10 * 4 + 10 * 2)  = 62 accès à la base de donnée.
Avec ma fonction, pour le même résultat:
3 + ( 10 * 1)  = 13 accès à la base de donnée.

et sans compter le reste de l'optimisation :)

Dernière modification par adjaya (2011-12-16 15:07:32)


Photo, Art et Création Numérique : http://benoit-grelier.photo7.fr/

Hors ligne

#3 2011-12-17 10:14:28

xave
Président
Lieu : commun
Inscription : 2004-05-06
Site Web

Re : Plugin Tag - Function setTags($cur,$pos_id)- optimisation

Ah mandieu, encore un Klingon... Dis-moi, camarade, tu es inscrit sur la liste Dev ? Tu as un accès en écriture sur le dépot Mercurial ? Nan parce que ce genre de truc, c'est matière à y entrer assez directement...


xave, asocial assez atypique (©Koz) , en 15ème année de http://xave.org/
RTFM. / Je ne lis pas la LOL-langue. / Je suis un gars désagréable, ne me parlez pas.

Hors ligne

#4 2011-12-17 10:15:27

xave
Président
Lieu : commun
Inscription : 2004-05-06
Site Web

Re : Plugin Tag - Function setTags($cur,$pos_id)- optimisation

(Surtout l'optimisation, on est tous plutôt pour l'optimisation, dans la bande...)


xave, asocial assez atypique (©Koz) , en 15ème année de http://xave.org/
RTFM. / Je ne lis pas la LOL-langue. / Je suis un gars désagréable, ne me parlez pas.

Hors ligne

#5 2011-12-17 11:51:32

adjaya
Membre
Lieu : Provence - Luberon
Inscription : 2006-09-05
Site Web

Re : Plugin Tag - Function setTags($cur,$pos_id)- optimisation

xave a écrit :

Ah mandieu, encore un Klingon... Dis-moi, camarade, tu es inscrit sur la liste Dev ? Tu as un accès en écriture sur le dépot Mercurial ? Nan parce que ce genre de truc, c'est matière à y entrer assez directement...

Non, pas inscrit, je ne savais même pas qu'on pouvait le faire, promis je regarde ca après les fêtes...
J'ai fait un clone à partir du miroir du dépôt et commencé à me familiariser avec mercurial. Mon idée est de faire des tests avec mon clone modifié pour être sûr que j'ai rien oublié.
Pour l'instant je n'ai fait aucun tests pour voir les effets de bord et consort.
D'ailleurs je viens de voir que j'ai oublié un détail dans ma fonction, j'écrase les autres meta_types du billet s'il y en a!
j'en suis là, sans tests toujours :

	public function setMetas($post_id,$metas,$type=null)
	{
		$this->checkPermissionsOnPost($post_id);
		
		$strReq = 'DELETE FROM '.$this->table.' '.
				'WHERE post_id = '.$post_id;
		if ($type !== null) {
			$strReq .= " AND meta_type = '".$this->con->escape($type)."' ";
		}
		if ($meta_id !== null) {
			$strReq .= " AND meta_id = '".$this->con->escape($meta_id)."' ";
		}
		$this->con->execute($strReq); #

		$sql = 'INSERT INTO '.$this->table.' (meta_id, post_id, meta_type) VALUES ';
		foreach ($this->splitMetaValues($metas) as $value)
		{
			$value = trim($value);
			if ($value === false) { continue; }
			
			$sql .= "('".
				$this->con->escape((string)$value)."', '".
				$this->con->escape((integer)$post_id)."', '".
				$this->con->escape((string)$type)."'),";
		}
		$this->con->execute(rtrim($sql,',')); #

		
		$strReq = 'SELECT meta_id, meta_type '.
				'FROM '.$this->table.' '.
				'WHERE post_id = '.$post_id.' ';
		$rs = $this->con->select($strReq); #
		
		$meta = array();
		while ($rs->fetch()) {
			$meta[$rs->meta_type][] = $rs->meta_id;
		}
		
		$post_meta = serialize($meta);
		$cur = $this->con->openCursor($this->core->prefix.'post');
		$cur->post_meta = $post_meta;
		$cur->update('WHERE post_id = '.$post_id); #
		
		$this->core->blog->triggerBlog(); #
	}

Si ca marche, je tombe à quatre le nombre d'accès à la base quelque-soit le nombre de tags.
Puisque j'y suis, je me dis autant faire le tour de la class.dc.meta et du plugin tag et  proposer après tests des modifications sur un dépôt sur le site bitbucket.

Dernière modification par adjaya (2011-12-17 11:55:18)


Photo, Art et Création Numérique : http://benoit-grelier.photo7.fr/

Hors ligne

#6 2011-12-29 08:09:11

adjaya
Membre
Lieu : Provence - Luberon
Inscription : 2006-09-05
Site Web

Re : Plugin Tag - Function setTags($cur,$pos_id)- optimisation

Bon, je note là quelques observations pendant que c'est frais pour pas oublier, sur
public function updateMeta($meta_id,$new_meta_id,$type=null,$post_type=null) de la class dcMeta.
Quelques typo dans le descriptif en commentaire de la méthode :

	/**
	Mass updates metadata for a given post_type.
	
	@param	meta_id		<b>integer</b>	old value
	@param	new_meta	<b>integer</b>	new value
	@param	type	<b>string</b>	meta type (if null, select all types)
	@param	post_type	<b>integer</b>	impacted post_type (if null, select all types)
	@return	<b>boolean</b>	true if at least 1 post has been impacted
	*/

deviens pour moi:

	/**
	Mass updates metadata for a given post_type.
	
	@param	meta_id		<b>string</b>	old value
	@param	new_meta	<b>string</b>	new value
	@param	type	<b>string</b>	meta type (if null, select all types)
	@param	post_type	<b>string</b>	impacted post_type (if null, select all types)
	@return	<b>boolean</b>	true if at least 1 post has been impacted
	*/

Ensuite la méthode propose la possibilité de faire l'update d'un meta_id sur tout les meta_types avec $type=null.
Ca ne peux pas marcher pour plusieurs raisons, car si $type est null, le bout de requête suivant est ignoré:

		if ($type !== null) {
			$plus = " AND meta_type = '%s' ";

hors plus loin dans la fonction on a

		if (!empty($to_remove))
		{
			$this->con->execute(sprintf($delReq,implode(',',$to_remove),
							$this->con->escape($meta_id),
							$this->con->escape($type)));

Là on vois que sprintf() prends l'argument $type, et s'il est null il est en trop et va générer une erreur.
on peux corriger le problème avec a la place de

		if ($type !== null) {
			$plus = " AND meta_type = '%s' ";

ceci:

		if ($type !== null) {
			$plus = "AND meta_type = '".$this->con->escape($type)."' ";

et ensuite, à la place de :

		if (!empty($to_remove))
		{
			$this->con->execute(sprintf($delReq,implode(',',$to_remove),
							$this->con->escape($meta_id),
							$this->con->escape($type)));

ceci :

		if (!empty($to_remove))
		{
			$this->con->execute(sprintf($delReq,implode(',',$to_remove),
							$this->con->escape($meta_id)));

Cette remarque est aussi valable pour

		if (!empty($to_update))
		{
			$this->con->execute(sprintf($updReq,$this->con->escape($new_meta_id),
							implode(',',$to_update),
							$this->con->escape($meta_id),
							$this->con->escape($type)));

qui deviens alors

		if (!empty($to_update))
		{
			$this->con->execute(sprintf($updReq,$this->con->escape($new_meta_id),
							implode(',',$to_update),
							$this->con->escape($meta_id)));

Bon, ca ne marchera pas mieux dans le cas par exemple d'un billet avec deux meta_type differents dont l'un a pour valeur $meta_id et l'autre $new_meta_id, car il va passer à la trappe de to_remove alors qu'il ne devrait pas dans ce cas précis car la fonction ne fait aucun contrôle de comparaisons sur les meta_type.

Conclusion, est-il vraiment pertinent d'ajouter cette possibilité d'adapter un meta_id sur tous les types?
Personnellement je pense que ce n'est pas utile et ne sera jamais utilisé, et ca complique la fonction si on veux éliminer tous les bugs existants dans l'état.


Photo, Art et Création Numérique : http://benoit-grelier.photo7.fr/

Hors ligne

#7 2012-01-06 14:05:43

adjaya
Membre
Lieu : Provence - Luberon
Inscription : 2006-09-05
Site Web

Re : Plugin Tag - Function setTags($cur,$pos_id)- optimisation

J'ai avancé sur mon idée d'optimisation, mais aussi de réorganisation du code, disponible ici :
https://bitbucket.org/adjaya/dotclear/c … dc500eea7c

C'est évidement parce-que j'ai une idée en tête, celle de pouvoir contrôler toutes nouvelles urls, que celles-ci soient issues de la table post, category ou meta. Cet impératif pour moi est motivé par l’évolution de mon plugin freeUrls qui permet de se passer de la signature post, category et tag des urls public de dotclear.
Cela crée de nouvelles contraintes quand à la détection des urls en doublons, pour cela j'avais besoin de deux behaviors, 'metaBeforeAdd' et 'metaBeforeUpdate'.

Pour ce qui est de l'optimisation je me suis amusé à faire un petit benchmark, histoire de m'en assurer.
En voici le code :

<?php
//***
$ob_meta = $core->meta;

$_post_id = $_REQUEST['id'];

$_meta_1 = 
'lui, toi, moi, eux, nous, vous, ils';
$_meta_2 =
'lui, toi, moi, autre, je, tu, il';

$_boucle = array(0,1,0,1,0,1,0,1,0,1);

$ob_meta->setPostMetaData($_post_id,'tag','');

$time_start = microtime(true);
foreach ($_boucle as $v) {
//code
	$_meta = ($v === 0) ? $_meta_1 : $_meta_2;

	$ob_meta->setPostMetaData($_post_id,'tag',$_meta);
//endcode
}
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "<p>Elapsed time whith setPostMetaData: ". $time." seconds</p>\n";

usleep(3000000);

$ob_meta->setPostMetaData($_post_id,'tag','');

$time_start = microtime(true);
foreach ($_boucle as $v) {
//code
	$_meta = ($v === 0) ? $_meta_1 : $_meta_2;

	$ob_meta->delPostMeta($_post_id,'tag');
			
	foreach ($ob_meta->splitMetaValues($_meta) as $_tag) {
		$ob_meta->setPostMeta($_post_id,'tag',$_tag);
	}
//endcode
}
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "<p>Elapsed time whith old method: ". $time." seconds</p>\n";
//***
?>

et le résultat sur 10 tests :

Elapsed time whith setPostMetaData: 0.019238948822 seconds
Elapsed time whith old method: 0.145311832428 seconds

Elapsed time whith setPostMetaData: 0.0276780128479 seconds
Elapsed time whith old method: 0.141902923584 seconds

Elapsed time whith setPostMetaData: 0.0256788730621 seconds
Elapsed time whith old method: 0.155315876007 seconds

Elapsed time whith setPostMetaData: 0.0201408863068 seconds
Elapsed time whith old method: 0.13499212265 seconds

Elapsed time whith setPostMetaData: 0.035383939743 seconds
Elapsed time whith old method: 0.145452976227 seconds

Elapsed time whith setPostMetaData: 0.0347990989685 seconds
Elapsed time whith old method: 0.0876040458679 seconds

Elapsed time whith setPostMetaData: 0.0211369991302 seconds
Elapsed time whith old method: 0.11737704277 seconds

Elapsed time whith setPostMetaData: 0.0227038860321 seconds
Elapsed time whith old method: 0.144399881363 seconds

Elapsed time whith setPostMetaData: 0.0336549282074 seconds
Elapsed time whith old method: 0.165102005005 seconds

Elapsed time whith setPostMetaData: 0.0279381275177 seconds
Elapsed time whith old method: 0.167669057846 seconds

J'ai fait d'autres différents tests, et le gain se fait sentir dès que l'on dépasse le nombre de 1 tag sur un billet.


Photo, Art et Création Numérique : http://benoit-grelier.photo7.fr/

Hors ligne

Vous n'êtes pas identifié(e).

Pied de page des forums

Sites map