<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>dbnewz &#187; MySQL</title>
	<atom:link href="http://www.dbnewz.com/category/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dbnewz.com</link>
	<description>le blog français sur les SGBD - MySQL, Oracle et plus...</description>
	<lastBuildDate>Fri, 22 Jan 2010 19:13:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Clés étrangères et actions de suppression/mise à jour</title>
		<link>http://www.dbnewz.com/2010/01/13/cles-etrangeres-et-actions/</link>
		<comments>http://www.dbnewz.com/2010/01/13/cles-etrangeres-et-actions/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 16:25:14 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Clés étrangères]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=468</guid>
		<description><![CDATA[Pour assurer l&#8217;intégrité référentielle entre 2 tables, on crée une clé étrangère. Actuellement avec MySQL, InnoDB et PBXT sont capables de gérer ces clés étrangères. Jusque là, rien de bien nouveau&#8230; Très souvent, on ajoute dans la définition de la clé étrangère l&#8217;instruction ON DELETE CASCADE ON UPDATE CASCADE de manière à ce qu&#8217;une mise [...]]]></description>
			<content:encoded><![CDATA[<p>Pour assurer l&#8217;intégrité référentielle entre 2 tables, on crée une clé étrangère. Actuellement avec MySQL, InnoDB et PBXT sont capables de gérer ces clés étrangères. Jusque là, rien de bien nouveau&#8230; Très souvent, on ajoute dans la définition de la clé étrangère l&#8217;instruction ON DELETE CASCADE ON UPDATE CASCADE de manière à ce qu&#8217;une mise à jour ou une suppression dans la table parente soit impactée dans la table enfant. Il existe pourtant d&#8217;autres actions, c&#8217;est ce que je vous propose de découvrir (ou de redécouvrir) dans cet article.</p>
<p><span id="more-468"></span></p>
<p>Pour plus de clarté, nous allons nous intéresser à 2 tables dont le schéma est le suivant :<br />
<code><br />
mysql&gt; CREATE TABLE parent (<br />
id INT NOT NULL AUTO_INCREMENT,<br />
data varchar(20) NOT NULL,<br />
PRIMARY KEY (id)<br />
) ENGINE = InnoDB;<br />
</code><br />
et<br />
<code><br />
mysql&gt; CREATE TABLE enfant (<br />
id int(11) NOT NULL AUTO_INCREMENT,<br />
id_parent int(11) NOT NULL,<br />
data2 varchar(20) NOT NULL,<br />
PRIMARY KEY (id),<br />
CONSTRAINT fk_parent FOREIGN KEY (id_parent) REFERENCES parent (id)<br />
) ENGINE=InnoDB<br />
</code><br />
Remplissons ces 2 tables avec quelques lignes pour faire nos tests :<br />
<code><br />
mysql&gt; INSERT INTO parent (data) VALUES ('test');<br />
mysql&gt; INSERT INTO enfant (id_parent,data2) VALUES (1,'test');<br />
mysql&gt; INSERT INTO enfant (id_parent,data2) VALUES (1,'test2');<br />
</code><br />
Que se passe-t-il maintenant quand nous essayons de supprimer la ligne de la table parente ?<br />
<code><br />
mysql&gt; DELETE FROM parent WHERE id = 1;<br />
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`enfant`, CONSTRAINT `fk_parent` FOREIGN KEY (`id_parent`) REFERENCES `parent` (`id`))<br />
</code><br />
Eh oui ! Quand on n&#8217;indique pas de clause particulière dans la définition de la clé étrangère, cela équivaut à indiquer la clause NO ACTION (ON DELETE NO ACTION ON UPDATE NO ACTION). Et cette action interdit la modification d&#8217;une ligne de la table parente si cette ligne est en liaison avec la table enfant par la clé étrangère. A noter : le mot-clé RESTRICT est équivalent à NO ACTION.</p>
<p>Testons maintenant le 3è mot-clé possible : SET NULL. Et pour cela, modifions la structure de la table enfant :<br />
<code><br />
mysql&gt; ALTER TABLE enfant DROP FOREIGN KEY fk_parent;<br />
mysql&gt; ALTER TABLE enfant ADD CONSTRAINT fk_parent FOREIGN KEY (id_parent) REFERENCES parent(id) ON DELETE SET NULL ON UPDATE SET NULL;<br />
ERROR 1005 (HY000): Can't create table 'test.#sql-4fb_33' (errno: 150)<br />
</code><br />
Ici MySQL ne permet pas la création de la clé étrangère. En effet, avec SET NULL, si la table parente est modifiée, les lignes liées par la clé étrangère sont mises à NULL dans la table enfant. Ceci ne fonctionne bien sûr que pour des colonnes qui peuvent être NULL, ce qui n&#8217;est pas le cas dans notre exemple. Vous pouvez vérifier le fonctionnement de SET NULL en ajoutant une nouvelle colonne autorisant les NULL dans nos 2 tables.</p>
<p>Enfin, pour terminer, la célèbre action CASCADE transmet la modification faite sur la table parent vers la table enfant :<br />
<code><br />
mysql&gt; ALTER TABLE enfant ADD CONSTRAINT fk_parent FOREIGN KEY (id_parent) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE CASCADE;<br />
mysql&gt; SELECT * FROM enfant;<br />
</code></p>
<pre>+----+-----------+-------+
| id | id_parent | data2 |
+----+-----------+-------+
|  1 |         1 | test  |
|  2 |         1 | test2 |
+----+-----------+-------+</pre>
<p><code><br />
mysql&gt; UPDATE parent SET id = id +1;<br />
mysql&gt; SELECT * FROM enfant;<br />
</code></p>
<pre>+----+-----------+-------+
| id | id_parent | data2 |
+----+-----------+-------+
|  1 |         2 | test  |
|  2 |         2 | test2 |
+----+-----------+-------+</pre>
<p>Il est également possible d&#8217;avoir des actions différentes pour la suppression et pour la mise à jour (par exemple ON DELETE RESTRICT ON UPDATE CASCADE).</p>
<p>Il reste encore 2 petites précisions à apporter :</p>
<ul>
<li> certains SGBD (c&#8217;est le cas de PostgreSQL par exemple) font une différence entre RESTRICT et NO ACTION : RESTRICT vérifie immédiatement l&#8217;intégrité référentielle alors que NO ACTION vérifie l&#8217;intégrité à la fin de l&#8217;exécution de la requete, ce qui laisse le temps à d&#8217;éventuelles triggers d&#8217;être déclenchés et à la contrainte d&#8217;intégrité d&#8217;être finalement respectée.</li>
<li> il existe dans la norme SQL une 5è action possible : SET DEFAULT, mais elle n&#8217;est pas supportée par MySQL</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2010/01/13/cles-etrangeres-et-actions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Comment réécrire une requête SQL ? Partie 2</title>
		<link>http://www.dbnewz.com/2009/12/21/comment-reecrire-une-requete-sql-partie-2/</link>
		<comments>http://www.dbnewz.com/2009/12/21/comment-reecrire-une-requete-sql-partie-2/#comments</comments>
		<pubDate>Mon, 21 Dec 2009 20:54:33 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[tuning]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=443</guid>
		<description><![CDATA[Dans le précédent post, nous avons optimisé une requête en abandonnant un des principes du SQL (dire au SGBD ce qu&#8217;on souhaite faire, mais pas comment le faire). Ici nous allons voir un exemple où le fait de penser en SQL va nous permettre de rendre performante une requête difficile à améliorer.
Nous repartons de la [...]]]></description>
			<content:encoded><![CDATA[<p>Dans le précédent post, nous avons optimisé une requête en abandonnant un des principes du SQL (dire au SGBD ce qu&#8217;on souhaite faire, mais pas comment le faire). Ici nous allons voir un exemple où le fait de penser en SQL va nous permettre de rendre performante une requête difficile à améliorer.</p>
<p><span id="more-443"></span>Nous repartons de la table du post précédent, remplie avec 500 000 enregistrements :<br />
<code>CREATE TABLE product (<br />
product_id int(11) NOT NULL AUTO_INCREMENT,<br />
category_id int(11) NOT NULL DEFAULT 0,<br />
reference varchar(20) NOT NULL DEFAULT '',<br />
name varchar(25) NOT NULL DEFAULT '',<br />
sold int(11) NOT NULL DEFAULT 0,<br />
PRIMARY KEY (product_id)<br />
) ENGINE=MyISAM;</code></p>
<p>Nous voulons, à partir de cette table de produits, trouver pour chaque catégorie le produit qui s&#8217;est le plus vendu.</p>
<p>Première idée : raisonner en terme de boucle, c&#8217;est-à-dire demander au SGBD de retrouver pour chaque catégorie le produit qui s&#8217;est le plus vendu. Cela donne en SQL la requête suivante :<br />
<code><br />
mysql&gt; SELECT sql_no_cache pdt.*<br />
FROM product pdt<br />
WHERE sold =<br />
(SELECT MAX(sold) FROM product<br />
WHERE category_id = pdt.category_id);<br />
</code></p>
<p>On note la sous-requête corrélée, qui traduit  en SQL notre idée de boucle à travers l&#8217;ensemble des catégories.</p>
<p>Temps d&#8217;exécution : très long&#8230; en effet j&#8217;ai arrêté l&#8217;exécution de la requête au bout de 20 mn, et toujours pas de résultat en vue à ce moment-là ! Un bon index est sans doute nécessaire&#8230;</p>
<p>Examinons le résultat de la commande EXPLAIN :<br />
<code><br />
mysql&gt; EXPLAIN SELECT...\G<br />
***************** 1. row *****************<br />
id: 1<br />
select_type: PRIMARY<br />
table: pdt<br />
type: ALL<br />
possible_keys: NULL<br />
key: NULL<br />
key_len: NULL<br />
ref: NULL<br />
rows: 500000<br />
Extra: Using where<br />
***************** 2. row *****************<br />
id: 2<br />
select_type: DEPENDENT SUBQUERY<br />
table: product<br />
type: ALL<br />
possible_keys: NULL<br />
key: NULL<br />
key_len: NULL<br />
ref: NULL<br />
rows: 500000<br />
Extra: Using where<br />
2 rows in set (0,00 sec)<br />
</code></p>
<p>Effectivement, ce n&#8217;est pas fameux : pour chaque ligne de la table product, MySQL va exécuter la sous-requête, qui elle-même fait un scan complet de la table product&#8230; On est dans une situation bien pire qu&#8217;un CROSS JOIN, ce qui explique la lenteur constatée.</p>
<p>Un index composite sur (category_id, sold) va bien nous permettre d&#8217;améliorer la sous-requête&#8230;<br />
<code><br />
mysql&gt; ALTER TABLE product add index idx_category_sold (category_id,sold);<br />
mysql&gt; EXPLAIN SELECT ...\G<br />
***************** 1. row *****************<br />
id: 1<br />
select_type: PRIMARY<br />
table: pdt<br />
type: ALL<br />
possible_keys: NULL<br />
key: NULL<br />
key_len: NULL<br />
ref: NULL<br />
rows: 500000<br />
Extra: Using where<br />
***************** 2. row *****************<br />
id: 2<br />
select_type: DEPENDENT SUBQUERY<br />
table: product<br />
type: ref<br />
possible_keys: idx_category_sold<br />
key: idx_category_sold<br />
key_len: 4<br />
ref: test.pdt.category_id<br />
rows: 500<br />
Extra: Using index<br />
2 rows in set (0,00 sec)<br />
</code></p>
<p>&#8230; mais il n&#8217;existe pas de moyen d&#8217;améliorer la requête principale.</p>
<p>Le temps d&#8217;exécution après ajout de l&#8217;index est maintenant de 2mn15, ce qui est encore loin d&#8217;être satisfaisant.</p>
<p>La limitation de notre requête, comme nous l&#8217;a montré la commande EXPLAIN, c&#8217;est que pour chacune des 500 000 lignes de la table, MySQL va devoir exécuter la sous-requête. Cela signifie que même en optimisant au mieux la sous-requête, celle-ci sera toujours exécutée 500 000 fois, ce qui est forcément couteux. Ajouter un index ne fait que limiter les dégâts, mais ne suffit pas pour obtenir des performances correctes.</p>
<p>La vraie solution à notre problème va consister à changer de point de vue sur la demande initiale formulée en langage courant, afin de pouvoir écrire la requête d&#8217;une toute autre manière, qui, espérons-le, sera plus efficace.</p>
<p>Nous allons donc raisonner de façon ensembliste. Avec notre table, il nous est possible de constituer deux ensembles : l&#8217;ensemble E1 des informations sur les produits (facile : SELECT * FROM product) et l&#8217;ensemble E2 des produits qui se sont le mieux vendus (facile aussi : SELECT category_id, MAX(sold) FROM product GROUP BY category_id). Si nous sommes capables de faire l&#8217;intersection entre E1 et E2, nous aurons résolu notre problème.</p>
<p>Or faire l&#8217;intersection de deux ensembles se traduit en SQL par une jointure entre deux tables. La solution est donc toute tracée :<br />
<code><br />
mysql&gt; SELECT sql_no_cache pdt.* FROM (<br />
SELECT category_id, MAX(sold) as maxi<br />
FROM product<br />
GROUP BY category_id<br />
) AS maxi_list<br />
INNER JOIN product pdt<br />
ON pdt.category_id = maxi_list.category_id<br />
AND pdt.sold = maxi_list.maxi;<br />
</code></p>
<p>EXPLAIN nous montre comment est exécutée cette nouvelle requête :<br />
<code><br />
mysql&gt; EXPLAIN SELECT ... \G<br />
***************** 1. row *****************<br />
id: 1<br />
select_type: PRIMARY<br />
table:<br />
type: ALL<br />
possible_keys: NULL<br />
key: NULL<br />
key_len: NULL<br />
ref: NULL<br />
rows: 1000<br />
Extra:<br />
***************** 2. row *****************<br />
id: 1<br />
select_type: PRIMARY<br />
table: pdt<br />
type: ref<br />
possible_keys: idx_category_sold<br />
key: idx_category_sold<br />
key_len: 8<br />
ref: maxi_list.category_id,maxi_list.maxi<br />
rows: 1<br />
Extra:<br />
***************** 3. row *****************<br />
id: 2<br />
select_type: DERIVED<br />
table: product<br />
type: range<br />
possible_keys: NULL<br />
key: idx_category_sold<br />
key_len: 4<br />
ref: NULL<br />
rows: 1001<br />
Extra: Using index for group-by<br />
3 rows in set (0,05 sec)<br />
</code></p>
<p>MySQL exécute d&#8217;abord la sous-requête puis place le résultat dans une table temporaire, qui est jointe à la table product. A noter que la jointure se fait avec deux conditions, qui sont nécessaires toutes les deux.</p>
<p>Quel est le temps d&#8217;exécution de cette requete ? 0.06s&#8230; Pas besoin de commentaire, le gain est vertigineux !</p>
<p>Ces deux articles nous ont donc permis de voir que la manière dont une requête est formulée peut avoir des conséquences très importantes sur les temps d&#8217;exécution. Il n&#8217;existe pas de règle pour savoir si une requête est bien écrite ou pas, mais quand vous rencontrez une requête utilisant de bons index mais qui est lente, il peut être très intéressant de réfléchir à son sens pour trouver une réécriture qui sera performante.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/12/21/comment-reecrire-une-requete-sql-partie-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comment réécrire une requête SQL ? Partie 1</title>
		<link>http://www.dbnewz.com/2009/11/26/que-signifie-reecrire-une-requete-sql/</link>
		<comments>http://www.dbnewz.com/2009/11/26/que-signifie-reecrire-une-requete-sql/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 21:04:03 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=406</guid>
		<description><![CDATA[Que faire quand une requête est lente ? Tout le monde vous dira qu&#8217;il faut commencer par regarder ce que dit EXPLAIN, puis ajouter ou modifier des index et s&#8217;il n&#8217;y a aucune amélioration, alors il faut essayer de réécrire la requête.
Déterminer quels sont les index à poser pour optimiser la requête est une tâche [...]]]></description>
			<content:encoded><![CDATA[<p>Que faire quand une requête est lente ? Tout le monde vous dira qu&#8217;il faut commencer par regarder ce que dit EXPLAIN, puis ajouter ou modifier des index et s&#8217;il n&#8217;y a aucune amélioration, alors il faut essayer de réécrire la requête.</p>
<p>Déterminer quels sont les index à poser pour optimiser la requête est une tâche relativement simple avec un peu d&#8217;habitude, mais que peut bien signifier la notion de réécriture d&#8217;une requête ?</p>
<p>Bien souvent, cette notion se limite à triturer les conditions de la clause WHERE de manière à isoler une colonne pour qu&#8217;un index soit utilisé. Et pourtant, il y a bien d&#8217;autres choses à imaginer, ce que nous allons aborder dans cet article.</p>
<p><span id="more-406"></span>Pour commencer, revenons très rapidement sur l&#8217;isolation des colonnes. Pour rappel, MySQL ne peut pas se servir d&#8217;un index sur une colonne si cette colonne fait partie d&#8217;une fonction.</p>
<p>Un petit exemple ?</p>
<pre>mysql&gt; EXPLAIN SELECT * FROM t WHERE UNIX_TIMESTAMP() - UNIX_TIMESTAMP(date_gen) &gt; 180\G
           id: 1
  select_type: SIMPLE
        table: t
         type: ALL
possible_keys: NULL
          key: NULL
           ...</pre>
<p>Ici, à cause de la fonction UNIX_TIMESTAMP(), MySQL refuse même d&#8217;étudier la possibilité d&#8217;utiliser l&#8217;index sur la colonne date_gen (ce qu&#8217;on voit dans la colonne possible_keys). Si par contre on réécrit un peu plus proprement notre condition et qu&#8217;on regarde de nouveau le plan d&#8217;exécution :</p>
<pre>mysql&gt; EXPLAIN SELECT * FROM t WHERE date_gen &lt; DATE_SUB(CURRENT_TIMESTAMP,INTERVAL 180 SECOND)\G
           id: 1
  select_type: SIMPLE
        table: t
         type: ALL
possible_keys: idx_date
          key: idx_date
          ...</pre>
<p>L&#8217;index sur la date est maintenant un candidat potentiel (toujours possible_keys) et il est utilisé (colonne key).</p>
<p>Ce genre de manipulations est en général simple à réaliser, venons-en donc à des techniques un peu moins connues.</p>
<p>Pour la suite de cet article, nous allons prendre des exemples avec une table product ayant les colonnes suivantes :<br />
<code><br />
CREATE TABLE `product` (<br />
`product_id` int(11) NOT NULL AUTO_INCREMENT,<br />
`category_id` int(11) NOT NULL DEFAULT '0',<br />
`reference` varchar(20) NOT NULL DEFAULT '',<br />
`name` varchar(25) NOT NULL DEFAULT '',<br />
`sold` int(11) NOT NULL DEFAULT '0',<br />
PRIMARY KEY (`product_id`)<br />
) ENGINE=MyISAM;<br />
</code></p>
<p>Cette table a été peuplée avec 500 000 enregistrements grâce à <a href="http://www.dbnewz.com/2008/07/07/mysqlslap-et-supersmack-deux-outils-de-benchmark-pour-mysql/">supersmack</a>.</p>
<p>Imaginons que nous voulons retrouver le premier produit qui a été inséré dans cette table dans la categorie n° 100. Facile :<br />
<code><br />
mysql&gt; SELECT MIN(product_id) FROM product WHERE category_id = 100;<br />
</code></p>
<p>Cette requête prend environ 0.9s à s&#8217;exécuter. Comme nous pensons que c&#8217;est un peu lent, nous allons essayer de l&#8217;améliorer, mais avec une contrainte forte : nous ne voulons pas modifier la structure de la table, et donc en particulier nous ne souhaitons pas ajouter un éventuel index.</p>
<p>La commande EXPLAIN nous apprend que le plan d&#8217;exécution choisi est un scan complet de la table, ce qui n&#8217;est pas une surprise puisque le seul index disponible (la clé primaire) ne risque pas de nous aider. Que faire alors ? Réécrire la requête bien sûr&#8230;</p>
<p>En réfléchissant bien, on peut se dire que si on scannait la clé primaire, on pourrait s&#8217;arrêter à la première valeur trouvée pour laquelle le champ category_id vaut 100. En effet, la clé primaire étant triée par ordre strictement croissant, la première valeur trouvée sera nécessairement la plus petite. D&#8217;où un premier essai :<br />
<code><br />
mysql&gt; SELECT MIN(product_id) FROM product USE INDEX(PRIMARY) WHERE category_id = 100;<br />
</code><br />
Malheureusement, un appel à EXPLAIN montre que MySQL ne veut toujours pas utiliser la clé primaire, idem avec FORCE INDEX. Il va donc falloir être un peu plus persuasif&#8230;</p>
<p>Nous allons changer la requête en remplaçant le MIN() par un tri avec une clause LIMIT :<br />
<code><br />
mysql&gt; SELECT product_id FROM product  WHERE category_id = 100 ORDER BY product_id ASC LIMIT 1;<br />
</code></p>
<p>Cette fois-ci, EXPLAIN nous indique bien un scan de la clé primaire. Extrait du résultat de la commande :</p>
<pre>mysql&gt; EXPLAIN SELECT product_id FROM product  WHERE category_id = 100 ORDER BY product_id ASC LIMIT 1\G
           id: 1
  select_type: SIMPLE
        table: product
         type: index
possible_keys: NULL
          key: PRIMARY</pre>
<p>Et maintenant, le temps d&#8217;exécution passe à 0.01s, soit un gain notable.</p>
<p>Voilà donc un cas intéressant, où en comprenant bien comment sont stockées les données et les index, on  peut réussir à réécrire une requête pour optimiser son exécution. Néanmoins, certains d&#8217;entre vous ont peut-être bondi en voyant cette réécriture.</p>
<p>En effet, nous avons tous appris que l&#8217;essence du SQL, c&#8217;est d&#8217;indiquer au SGBD ce qu&#8217;on souhaite trouver en laissant toute latitude au SGBD pour déterminer la manière la plus efficace d&#8217;effectuer la requête. Ici, non seulement, on indique comment faire la requête mais en plus, on perd le sens de la requête, l&#8217;appel à la fonction MIN() étant beaucoup plus explicite sur notre intention que la clause ORDER BY avec un LIMIT. Parfois, il faut pourtant juste être pragmatique et laisser tomber les grands principes au profit de la performance.</p>
<p>A noter avant de clore cette 1ère partie que la même requête initiale avec un MAX() n&#8217;aurait pas pu être réécrite d&#8217;une manière similaire. Notre technique de réécriture repose en effet sur le tri croissant de la clé primaire et il aurait fallu un tri décroissant sur la clé primaire pour que la technique fonctionne avec le MAX().</p>
<p>La seconde partie de cette article sera consacrée à des exemples de réécriture où le fait de penser en SQL sera bénéfique. Ouf, nous pourrons nous réconcilier avec les puristes du SQL.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/11/26/que-signifie-reecrire-une-requete-sql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Conférences MySQL au Forum PHP</title>
		<link>http://www.dbnewz.com/2009/10/20/conferences-mysql-au-forum-php/</link>
		<comments>http://www.dbnewz.com/2009/10/20/conferences-mysql-au-forum-php/#comments</comments>
		<pubDate>Tue, 20 Oct 2009 12:48:47 +0000</pubDate>
		<dc:creator>pébé</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=389</guid>
		<description><![CDATA[Le MUG est partenaire du Forum PHP, qui se tient les 12 et 13 novembre 2009, à la Cité des Sciences et de l&#8217;Industrie.
Au programme des conférences dédiées à MySQL et MariaDB :

mysqlnd / &#171;&#160;MySQL native driver for PHP&#160;&#187; : Les améliorations de la stack
Au secours, ma base de données fait ramer mon application !
LeMug [...]]]></description>
			<content:encoded><![CDATA[<p>Le MUG est partenaire du Forum PHP, qui se tient les 12 et 13 novembre 2009, à la Cité des Sciences et de l&#8217;Industrie.</p>
<p>Au programme des conférences dédiées à MySQL et MariaDB :</p>
<ul>
<li>mysqlnd / &laquo;&nbsp;MySQL native driver for PHP&nbsp;&raquo; : Les améliorations de la stack</li>
<li>Au secours, ma base de données fait ramer mon application !</li>
<li>LeMug : MariaDB, the future of MySQL avec Michael Widenius aka Monty</li>
<li>Retour d&#8217;expérience sur l&#8217;utilisation de MySQL Chez Orange</li>
<li>Réplication MySQL : retours d&#8217;expérience</li>
</ul>
<p>Participez à cet événement et bénéficiez d&#8217;une offre exceptionnelle :</p>
<p>les deux journées du Forum PHP<br />
+<br />
<a href="https://lemugfr.cotiserenligne.fr/">l&#8217;adhésion 2009/2010 au MySQL User Group France</a></p>
<p>pour 140 euros au lieu de 200 euros!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/10/20/conferences-mysql-au-forum-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>InnoDB, verrouillage, transactions et index</title>
		<link>http://www.dbnewz.com/2009/09/30/innodb-verrouillage-transactions-et-index/</link>
		<comments>http://www.dbnewz.com/2009/09/30/innodb-verrouillage-transactions-et-index/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 15:49:16 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=360</guid>
		<description><![CDATA[Bin voyons, tout ça en un seul post ! On se rapproche doucement de Noël, mais quand même !
Je m&#8217;explique&#8230;
Je me suis intéressé récemment aux instructions SELECT &#8230; LOCK IN SHARE MODE et SELECT &#8230; FOR UPDATE, qui sont censées permettre de verrouiller explicitement des lignes pour les tables InnoDB.
On comprend maintenant les deux premiers [...]]]></description>
			<content:encoded><![CDATA[<p>Bin voyons, tout ça en un seul post ! On se rapproche doucement de Noël, mais quand même !<br />
Je m&#8217;explique&#8230;</p>
<p>Je me suis intéressé récemment aux instructions SELECT &#8230; LOCK IN SHARE MODE et SELECT &#8230; FOR UPDATE, qui sont censées permettre de verrouiller explicitement des lignes pour les tables InnoDB.<br />
On comprend maintenant les deux premiers termes du titre <img src='http://www.dbnewz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><span id="more-360"></span>Pour mes test, je crée une table avec quelques enregistrements :<br />
<code>mysql&gt; CREATE TABLE innotest (<br />
id int(11) NOT NULL,<br />
col varchar(10) DEFAULT NULL<br />
) ENGINE=InnoDB;</code></p>
<p><code>mysql&gt; INSERT INTO innotest (id,col) VALUES (1,'aaa'),(2,'bbb'),(3,'ccc'),(4,'ddd'),(5,'eee');</code></p>
<p>1er essai :<br />
J&#8217;ouvre une 1ère session :<br />
<code>mysql&gt; SELECT * FROM innotest WHERE col &gt; 'c%' LOCK IN SHARE MODE;<br />
+----+------+<br />
| id | col  |<br />
+----+------+<br />
|  3 | ccc  |<br />
|  4 | ddd  |<br />
|  5 | eee  |<br />
+----+------+<br />
3 rows in set (0,00 sec)</code></p>
<p>Si je comprends bien, LOCK IN SHARE MODE pose un verrou partagé sur les lignes d&#8217;id 3, 4 et 5. Donc, normalement, si j&#8217;ouvre une autre session et que j&#8217;essaie de poser un verrou exclusif sur la ligne d&#8217;id 5, ma requête devrait être bloquée jusqu&#8217;à ce que je lève mon verrou partagé.</p>
<p>Essayons :<br />
<!--more--><br />
J&#8217;ouvre une 2nde session :<br />
<code>mysql&gt; SELECT * FROM innotest WHERE id=5 FOR UPDATE;<br />
+----+------+<br />
| id | col  |<br />
+----+------+<br />
|  5 | eee  |<br />
+----+------+<br />
1 row in set (0,00 sec)</code></p>
<p>Hum ? La requête dans la 2nde session n&#8217;est pas bloquée, ce qui signifie que soit le verrou partagé n&#8217;a pas été posé, soit le verrou a bien été posé mais a été relâché d&#8217;une manière ou d&#8217;une autre.<br />
Direction donc le <a href="http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html">manuel de référence</a>.</p>
<p>Bon sang, mais c&#8217;est bien sûr ! Les verrous sont relâchés à la fin des transactions et comme je suis en mode AUTOCOMMIT, la transaction se termine tout de suite après chacun de mes SELECT.<br />
Conclusion : il faut refaire la même chose, mais dans une transaction (3è terme du titre <img src='http://www.dbnewz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> )</p>
<p>2è essai:<br />
J&#8217;ouvre une 1ère session :<br />
<code>mysql&gt; START TRANSACTION;<br />
Query OK, 0 rows affected (0,00 sec)</code></p>
<p><code>mysql&gt; SELECT * FROM innotest WHERE col &gt; 'c%' LOCK IN SHARE MODE;<br />
+----+------+<br />
| id | col  |<br />
+----+------+<br />
|  3 | ccc  |<br />
|  4 | ddd  |<br />
|  5 | eee  |<br />
+----+------+<br />
3 rows in set (0,00 sec)</code></p>
<p>puis une 2nde session :<br />
<code>mysql&gt; START TRANSACTION;<br />
Query OK, 0 rows affected (0,00 sec)</code></p>
<p><code>mysql&gt; SELECT * FROM innotest WHERE id=5 FOR UPDATE;</code></p>
<p>Cette fois, je ne récupère pas la main sur mon SELECT &#8230; FOR UPDATE car ce SELECT ne peut pas acquérir le verrou exclusif sur la ligne d&#8217;id 5 à cause du SELECT de l&#8217;autre session qui a déjà un verrou partagé sur cette ligne. Ouf ! Je vérifie bien que le SELECT &#8230; LOCK IN SHARE MODE a posé des verrous comme je le souhaitais.</p>
<p>Si maintenant, je fais un COMMIT dans ma 1ère session, le verrou partagé est levé et le SELECT &#8230; FOR UPDATE peut alors se terminer.</p>
<p>A noter que dans la 2ème session, je n&#8217;ai pas réellement besoin du START TRANSACTION, puisque ce sont les verrous posés par le SELECT &#8230; LOCK IN SHARE MODE qui m&#8217;intéressent ici.</p>
<p>Ce point étant clarifié, passons à une autre vérification : le LOCK IN SHARE MODE a-t-il bien verrouillé uniquement les lignes d&#8217;id 3, 4 et 5 ?</p>
<p>Facile : il suffit de répéter la même séquence que dans le 2è essai mais en modifiant la requête dans la 2è session pour demander un verrou exclusif sur la ligne d&#8217;id 1. Cette ligne n&#8217;étant pas censée être verrouillée, je dois pouvoir obtenir le verrou immédiatement.</p>
<p>3è essai :<br />
1ère session :<br />
<code>mysql&gt; START ...</code></p>
<p>2nde session :<br />
<code>mysql&gt; SELECT * FROM innotest WHERE id=1 FOR UPDATE;</code></p>
<p>Et là, c&#8217;est le drame ! Le verrou exclusif ne peut pas être acquis et donc la requête est bloquée. Il n&#8217;y a qu&#8217;un seul suspect possible, c&#8217;est le SELECT &#8230; LOCK IN SHARE MODE de la 1ère session.</p>
<p>Comme bien souvent, pour comprendre ce qui se passe dans une requête, un petit coup d&#8217;EXPLAIN est bien utile :<br />
<code>mysql&gt; EXPLAIN SELECT * FROM innotest WHERE col &gt; 'c%' LOCK IN SHARE MODE\G<br />
******************* 1. row *****************<br />
id: 1<br />
select_type: SIMPLE<br />
table: innotest<br />
type: ALL<br />
...</code></p>
<p>Maintenant, tout est clair ! Le type ALL indique un full table scan, or comme InnoDB acquiert les verrous au fur et à mesure qu&#8217;il en a besoin, dans ce cas, il lui faut acquérir un verrou sur toutes les lignes de la table. Evidemment, ce n&#8217;était pas très facile à deviner&#8230;</p>
<p>Tout espoir est-il perdu de faire verrouiller par une transaction une partie des lignes et de faire verrouiller par une autre transaction une autre partie des lignes ? A priori, si InnoDB était capable dans mon 1er SELECT de trouver les lignes 3, 4 et 5 sans faire de full table scan, ça pourrait être possible.</p>
<p>Comment faire ce miracle ? Avec un index sur col, bien sûr ! (Et voilà, 4è terme du titre <img src='http://www.dbnewz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> )</p>
<p><code>mysql&gt; ALTER TABLE innotest ADD INDEX idx_col(col);</code></p>
<p>et on recommence la séquence du 3è essai :<br />
1ère session :<br />
&#8230;</p>
<p>2nde session :<br />
<code>mysql&gt; SELECT * FROM innotest WHERE id=1 FOR UPDATE;</code></p>
<p>Aïe, ça bloque encore et toujours <img src='http://www.dbnewz.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p>
<p>Un EXPLAIN sur le SELECT &#8230; LOCK IN SHARE MODE montre pourtant bien que l&#8217;index est utilisé :<br />
<code>mysql&gt; EXPLAIN SELECT * FROM innotest WHERE col &gt; 'c%' LOCK IN SHARE MODE\G<br />
************* 1. row ***********<br />
id: 1<br />
select_type: SIMPLE<br />
table: innotest<br />
type: range<br />
possible_keys: idx_col<br />
key: idx_col<br />
...<br />
</code><br />
Oui mais maintenant, le problème vient du 2è SELECT. Comme il n&#8217;y a pas d&#8217;index sur id, MySQL fait un full table scan pour résoudre la requête (c&#8217;est confirmé par un appel à EXPLAIN) et pose des verrous exclusifs sur toutes les lignes rencontrées&#8230;sauf que les lignes 3 à 5 ont déjà un verrou partagé : il n&#8217;est donc pas possible de poser le verrou exclusif, ce qui bloque toute la requête.</p>
<p>La solution passe là encore par un index, mais cette fois-ci sur id. Ou alors, en conservant uniquement l&#8217;index sur col, il faut réécrire la requête pour qu&#8217;elle fasse intervenir l&#8217;index, par exemple :<br />
<code>mysql&gt; SELECT * FROM innotest WHERE name='aaa' FOR UPDATE;</code></p>
<p>Evidemment, dans la vraie vie, il n&#8217;est pas toujours possible de réécrire ainsi ses requêtes, mieux vaut donc poser les bons index.</p>
<p>Cerise sur le gâteau pour finir, en ne conservant que l&#8217;index sur col, on peut faire apparaître une jolie deadlock en pensant ne verrouiller que des lignes différentes :<br />
1ère session:<br />
<code>mysql&gt; START TRANSACTION;<br />
Query OK, 0 rows affected (0,00 sec)</code></p>
<p><code>mysql&gt; SELECT * FROM innotest WHERE col &gt; 'c%' LOCK IN SHARE MODE;</code></p>
<p>2nde session :<br />
<code>mysql&gt; SELECT * FROM innotest WHERE id=1 FOR UPDATE;</code></p>
<p>puis de retour dans la 1ère session :<br />
<code>mysql&gt; SELECT * FROM innotest where col='bbb' LOCK IN SHARE MODE;</code></p>
<p>ce qui provoque dans la 2è session :<br />
<code>ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction</code></p>
<p>Moralité de l&#8217;histoire : votre bonne conscience vous répète constamment que les index sont vitaux. Faites plaisir à votre conscience : posez des index ! (pertinents bien sûr&#8230;)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/09/30/innodb-verrouillage-transactions-et-index/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Securich &#8211; Darren Cassar</title>
		<link>http://www.dbnewz.com/2009/08/23/securich-darren-cassar/</link>
		<comments>http://www.dbnewz.com/2009/08/23/securich-darren-cassar/#comments</comments>
		<pubDate>Sun, 23 Aug 2009 12:36:12 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[5.1]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OpenSQLCamp]]></category>
		<category><![CDATA[outils]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=349</guid>
		<description><![CDATA[Darren s&#8217;est occupé récemment d&#8217;une migration de Sybase vers MySQL. Et il s&#8217;est aperçu à cette occasion que la gestion des utilisateurs sous MySQL n&#8217;est pas sans défaut. Par exemple, il n&#8217;est pas possible de créer des rôles, il n&#8217;est pas possible de donner à un utilisateur des droits sur toutes les tables sauf une, [...]]]></description>
			<content:encoded><![CDATA[<p>Darren s&#8217;est occupé récemment d&#8217;une migration de Sybase vers MySQL. Et il s&#8217;est aperçu à cette occasion que la gestion des utilisateurs sous MySQL n&#8217;est pas sans défaut. Par exemple, il n&#8217;est pas possible de créer des rôles, il n&#8217;est pas possible de donner à un utilisateur des droits sur toutes les tables sauf une, il n&#8217;est pas possible de connaître le degré de complexité d&#8217;un mot de passe&#8230;</p>
<p>Pour essayer de pallier à tous ces défauts, Darren a créé un outil : <a href="http://www.securich.com">Securich,</a> installable sur tout serveur MySQL 5.1. Cet outil permet, à l&#8217;aide d&#8217;appels à des procédures stockées, de manipuler les utilisateurs et leurs droits. Attention tout de même, le développement de Securich a commencé il y a peu de temps et le code est encore expérimental. Il reste pas mal de fonctionnalités que Darren voudrait implémenter et quelques bugs gênants : par exemple, si vous installez Securich sur un serveur contenant des utilisateurs, Securich va effacer tous les utilisateurs sans vous en avertir&#8230;</p>
<p>L&#8217;initiative est en tout cas intéressante car il reste effectivement pas mal de travail pour que MySQL présente autant de fonctionnalités sur les utilisateurs et les droits que d&#8217;autres produits.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/08/23/securich-darren-cassar/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL Sandbox 3 &#8211; Giuseppe Maxia</title>
		<link>http://www.dbnewz.com/2009/08/23/mysql-sandbox-3-giuseppe-maxia/</link>
		<comments>http://www.dbnewz.com/2009/08/23/mysql-sandbox-3-giuseppe-maxia/#comments</comments>
		<pubDate>Sun, 23 Aug 2009 09:43:07 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OpenSQLCamp]]></category>
		<category><![CDATA[outils]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=342</guid>
		<description><![CDATA[Nous avons tous régulièrement besoin de monter rapidement un ou plusieurs serveurs MySQL pour tester telle ou telle fonctionnalité. Et évidemment, c&#8217;est toujours quand on veut aller vite qu&#8217;on fait des erreurs et qu&#8217;on se retrouve avec des serveurs qui ne démarrent pas. MySQL Sandbox a été créée pour nous aider dans cette situation. Giuseppe [...]]]></description>
			<content:encoded><![CDATA[<p>Nous avons tous régulièrement besoin de monter rapidement un ou plusieurs serveurs MySQL pour tester telle ou telle fonctionnalité. Et évidemment, c&#8217;est toujours quand on veut aller vite qu&#8217;on fait des erreurs et qu&#8217;on se retrouve avec des serveurs qui ne démarrent pas. MySQL Sandbox a été créée pour nous aider dans cette situation. Giuseppe s&#8217;est en effet trouvé de nombreuses fois dans la situation où il perdait énormément de temps à monter des environnements jetables et il a imaginé un script permettant d&#8217;automatiser cette création d&#8217;environnements jetables.</p>
<p>Sans entrer dans le détail des commandes (voir pour cela <a href="https://launchpad.net/mysql-sandbox">la page sur Launchpad</a>), MySQL Sandbox permet de créer en une ligne de commande des environnements complets et variés : un serveur, plusieurs serveurs indépendants, un maître-plusieurs esclaves&#8230;Il est même possible de créer, toujours en une seule ligne, une réplication circulaire entre N serveurs ! Le script permet également de démarrer, arrêter, effacer chacun des serveurs ainsi créés ou de faire une opération pour tous les serveurs à la fois.</p>
<p>Ca faisait un moment que je voulais prendre un peu de temps pour voir ce qu&#8217;il était possible de faire avec MySQL Sandbox, maintenant c&#8217;est sûr : je vais m&#8217;y mettre !</p>
<p>A voir également sur le sujet : <a href="http://www.dbnewz.com/2008/10/10/15-secondes-pour-installer-une-replication-mysql-avec-mysql-sandbox-pari-tenu/">un précédent article d&#8217;Arnaud</a>, sur dbnewz bien sûr !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/08/23/mysql-sandbox-3-giuseppe-maxia/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A better MySQLTuner &#8211; Sheeri K. Cabral</title>
		<link>http://www.dbnewz.com/2009/08/22/a-better-mysqltuner-sheeri-k-cabral/</link>
		<comments>http://www.dbnewz.com/2009/08/22/a-better-mysqltuner-sheeri-k-cabral/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 13:39:38 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OpenSQLCamp]]></category>
		<category><![CDATA[tuning]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=334</guid>
		<description><![CDATA[MySQLTuner est un script Perl qui produit un rapport sur la configuration de votre serveur MySQL et donne des pistes d&#8217;optimisation. On peut bien sûr s&#8217;interroger sur la manière dont l&#8217;analyse est faite et surtout sur la pertinence des recommendations. C&#8217;est exactement l&#8217;exercice qu&#8217;a fait Sheeri pour nous, en examinant le script sur toutes ses [...]]]></description>
			<content:encoded><![CDATA[<p>MySQLTuner est un script Perl qui produit un rapport sur la configuration de votre serveur MySQL et donne des pistes d&#8217;optimisation. On peut bien sûr s&#8217;interroger sur la manière dont l&#8217;analyse est faite et surtout sur la pertinence des recommendations. C&#8217;est exactement l&#8217;exercice qu&#8217;a fait Sheeri pour nous, en examinant le script sur toutes ses coutures.</p>
<p>Il en ressort que pas mal d&#8217;affirmations et de recommendations sont hardcodées et ne tiennent absolument pas compte des spécificités de votre base. Un exemple ? Si le cache de requêtes est désactivé, alors le script va systématiquement vous remonter qu&#8217;il s&#8217;agit d&#8217;un problème, même si vous avez sciemment désactivé ce cache.</p>
<p>A partir de toutes ces constatations, Sheeri a commencé à faire évoluer le script, en ajoutant pour l&#8217;instant quelques options intéressantes, comme celle permettant de formater le rapport de manière à le rendre facilement lisible par un tableur : il devient ainsi plus facile de voir l&#8217;évolution de certains indicateurs dans le temps en lançant le script à intervalles réguliers. A suivre !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/08/22/a-better-mysqltuner-sheeri-k-cabral/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>OpenSQLCamp : Sharding for the masses</title>
		<link>http://www.dbnewz.com/2009/08/22/opensqlcamp-sharding-for-the-masses/</link>
		<comments>http://www.dbnewz.com/2009/08/22/opensqlcamp-sharding-for-the-masses/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 09:02:43 +0000</pubDate>
		<dc:creator>stephane</dc:creator>
				<category><![CDATA[5.1]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OpenSQLCamp]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=328</guid>
		<description><![CDATA[Ce week-end a lieu à côté de Bonn l&#8217;OpenSQLCamp, en parallèle de la FrOSCon. Giuseppe Maxia nous parle aujourd&#8217;hui d&#8217;une technique utilisée dans certaines applications à fort trafic : le sharding. Mais à quoi sert le sharding ?
Quand on commence une application, un seul serveur SQL suffit généralement à absorber la charge. Si le trafic [...]]]></description>
			<content:encoded><![CDATA[<p>Ce week-end a lieu à côté de Bonn l&#8217;OpenSQLCamp, en parallèle de la <a href="http://www.froscon.de/en/">FrOSCon</a>. <a href="http://datacharmer.blogspot.com/">Giuseppe Maxia</a> nous parle aujourd&#8217;hui d&#8217;une technique utilisée dans certaines applications à fort trafic : le sharding. Mais à quoi sert le sharding ?</p>
<p>Quand on commence une application, un seul serveur SQL suffit généralement à absorber la charge. Si le trafic augmente et que les performances du serveur commencent à s&#8217;écrouler, on peut utiliser la réplication. Mais la réplication ne permet que d&#8217;augmenter le nombre de lectures possibles (read scaling) et pas le nombre d&#8217;écritures (write scaling). Cette limitation provient du fonctionnement même de la réplication car toutes les écritures doivent arriver sur le serveur maître. On peut alors imaginer de séparer les données selon certaines règles (dépendantes de l&#8217;application) de manière à avoir plusieurs masters sur lesquels on peut utiliser la réplication. Et voilà, nous venons d&#8217;inventer le sharding.</p>
<p>Giuseppe nous explique que le sharding est simple à mettre en place : il suffit de créer des règles permettant de dispatcher les données entre les différents masters. Malheureusement, le sharding est fragile : si, par exemple, vous changez les règles de dispatch, vous risquez de casser vos shards ! Pour simplifier le sharding, il existe un moteur de stockage récent, installable en tant que plugin pour MySQL 5.1 : Spider. Spider est basé sur le partitionnement et permet de créer des tables sur un serveur dont les données seront stockées sur des hosts distants. En gros, on utilise une pincée de partitionnement et une pincée de Federated&#8230;</p>
<p>Les démonstrations faites par Giuseppe montrent quand même que si Spider peut nous simplifier la tâche du sharding, la mise en place de tables avec Spider n&#8217;est pas si simple et demande un peu de doigté et de réflexion&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/08/22/opensqlcamp-sharding-for-the-masses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Désactiver les clés étrangères</title>
		<link>http://www.dbnewz.com/2009/07/15/desactiver-les-cles-etrangeres/</link>
		<comments>http://www.dbnewz.com/2009/07/15/desactiver-les-cles-etrangeres/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 21:00:29 +0000</pubDate>
		<dc:creator>arnaud</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[pratique]]></category>

		<guid isPermaLink="false">http://www.dbnewz.com/?p=321</guid>
		<description><![CDATA[Une petite &#171;&#160;astuce&#160;&#187; pour se remettre dans le bain du blogging&#8230; Comme vous avez pu le constater la fréquence de mise à jour a un peu diminuée depuis notre retour de la MySQL Conf, corrigeons cela avec cette petite remise en jambe à classer dans la catégorie &#171;&#160;pratique&#160;&#187;.
La désactivation du contrôle des clés étrangères est [...]]]></description>
			<content:encoded><![CDATA[<p>Une petite &laquo;&nbsp;astuce&nbsp;&raquo; pour se remettre dans le bain du blogging&#8230; Comme vous avez pu le constater la fréquence de mise à jour a un peu diminuée depuis notre retour de la MySQL Conf, corrigeons cela avec cette petite remise en jambe à classer dans la catégorie &laquo;&nbsp;pratique&nbsp;&raquo;.</p>
<p>La désactivation du contrôle des clés étrangères est intéressante lorsque vous devez exécuter sur votre serveur MySQL un script de création de tables par exemple. Il se peut dans ce cas que l&#8217;ordre de création des différentes tables ne soit pas &laquo;&nbsp;logique&nbsp;&raquo;.</p>
<p>J&#8217;entends par là qu&#8217;une table A peut contenir une contrainte basée sur une clé étrangère référençant le champ d&#8217;une table B&#8230; qui n&#8217;existe pas encore ! La &laquo;&nbsp;logique&nbsp;&raquo; voudrait que les tables soient inscrites dans le script selon les liens qui existent entre elles mais cela n&#8217;est pas toujours le cas.</p>
<p>Cette opération de classement pouvant s&#8217;avérer fastidieuse à effectuer manuellement, vous pouvez vous affranchir des vérifications effectuées par le SGBD concernant les clés étrangères en utilisant la commande suivante :</p>
<p><code>mysql&gt; <strong>SET foreign_key_checks = 0;</strong></code></p>
<p>Vous êtes ainsi tranquille le temps de créer vos tables. Réactiver ce contrôle n&#8217;est pas plus compliqué :</p>
<p><code>mysql&gt; <strong>SET foreign_key_checks = 1;</strong></code></p>
<p><a href="http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html" target="_blank">Le chapitre de la documentation</a> correspondant aux foreign keys nous indique que c&#8217;est d&#8217;ailleurs la technique employée par mysqldump.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dbnewz.com/2009/07/15/desactiver-les-cles-etrangeres/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
