<?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>Le blog de SQLpro &#187; Langage SQL (norme)</title>
	<atom:link href="https://blog.developpez.com/sqlpro/pcategory/langage-sql-norme/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/sqlpro</link>
	<description>Le SQL pour SQL Server, PostGreSQL et tous les autres SGBDR</description>
	<lastBuildDate>Thu, 15 Oct 2020 12:59:17 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Modèle générique vs modèle spécifique</title>
		<link>https://blog.developpez.com/sqlpro/p13183/langage-sql-norme/modele-generique-vs-modele-specifique</link>
		<comments>https://blog.developpez.com/sqlpro/p13183/langage-sql-norme/modele-generique-vs-modele-specifique#comments</comments>
		<pubDate>Fri, 10 Aug 2018 08:04:43 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[bases de données]]></category>
		<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[Modélisation des donées]]></category>
		<category><![CDATA[comparaison]]></category>
		<category><![CDATA[enfant]]></category>
		<category><![CDATA[facilité]]></category>
		<category><![CDATA[famille]]></category>
		<category><![CDATA[générique]]></category>
		<category><![CDATA[héritage]]></category>
		<category><![CDATA[modélisation]]></category>
		<category><![CDATA[parent]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[qualité]]></category>
		<category><![CDATA[spécifique]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=842</guid>
		<description><![CDATA[Dans le cadre d&#8217;un héritage de données ayant de multiples enfants aux caractéristiques très diverses, est-il préférable de concevoir un modèle de données générique ou un modèle de données spécifique ? De nombreux jeunes développeurs pensent naïvement qu&#8217;un modèle générique est plus facile&#8230; Mais c&#8217;est souvent une erreur qu&#8217;il faudra payer au prix fort une [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Dans le cadre d&rsquo;un héritage de données ayant de multiples enfants aux caractéristiques très diverses, est-il préférable de concevoir un modèle de données générique ou un modèle de données spécifique ? De nombreux jeunes développeurs pensent naïvement qu&rsquo;un modèle générique est plus facile&#8230; Mais c&rsquo;est souvent une erreur qu&rsquo;il faudra payer au prix fort une fois l&rsquo;application fonctionnelle. Démonstration&#8230;<br />
<span id="more-842"></span><br />
Je suis partit initialement de ce post :</p>
<p><a href="https://www.developpez.net/forums/d1881400/bases-donnees/langage-sql/avis-l-architecture-base-donnees-choix-l-option/" rel="noopener" target="_blank">Avis sur l&rsquo;architecture de ma base de données (choix de l&rsquo;option)</a></p>
<p>La demande étant la suivante :</p>
<p><em>J&rsquo;ai 30 familles de critères. Chaque famille comporte un nombre variable de critères pour un total d&rsquo;environ 600 critères.<br />
Chaque critère appartient à une seule famille de sorte que les 600 sont à répartir dans les 30 familles.<br />
Ma question:<br />
&#8211; devrais-je créer <strong>une table par famille</strong> et insérer dans chaque table les critères qui lui appartiennent; (solution 1)<br />
ou alors:<br />
&#8211; créer <strong>une table contenant les 30 familles et une autre contenant les 600 critères</strong>. Ensuite, créer les relations qui lient chaque famille à ses critères et/ou inversement. (solution 2)</em></p>
<p>et ma réponse :</p>
<p><em>Pour qu&rsquo;une base réponde bien en terme de performances, on doit tout faire pour minimiser les IO.<br />
&#8211; Dans votre solution 1, les performances seront bonne si la plupart des requêtes portent sur plusieurs critères d&rsquo;une même famille<br />
&#8211; Dans votre solution 2, les performances seront bonne si la plupart des requêtes portent sur un seul critère.</em></p>
<p>Cependant un jeune internaute peu avisé, affirmait avec force que :</p>
<p><em>pour moi la solution 2 est la + simple à mettre en place.<br />
et le nombre d&rsquo;enregistrements ne justifie pas la solution 1..<br />
tout dépend de votre SGBD (pas précisé..), mais dans tous les cas, il suffit de mettre des ID numérique pour que les requêtes soient optimisées. Créez vos tables avec des id uniques (sous Oracle on peux utiliser les séquences) et vous aurez des traitements optimisées au mieux&#8230; mais bon, je vous rassure, sous Oracle, même avec des clefs en Varchar, pour 600 enregistrements, y a aucun pb..<br />
si je vois bien, vous aurez donc 3 tables avec les clef suivante :<br />
&#8211; FAMILLE (Pk : ID_FAMILLE)<br />
&#8211; FAMILLE_CRITERE (Pk : ID_FAMILLE, ID_CRITERE)<br />
&#8211; CRITERE (Pk : ID_CRITERE)<br />
Relations :<br />
¤ Famille &#8211;&gt; FAMILLE_CRITERES &lt;&#8212; CRITERE<br />
famille_critere ne contenant que le couple ID_FAMILLE, ID_CRITERE (on parle de table intermédiaire)  </em></p>
<p>Ce à quoi je répondais :</p>
<p><em>La solution 2 est correcte si vous ne requêtez JAMAIS plus d&rsquo;un critère à la fois. Elle est déjà moins performante à l’insertion/la mise à jour des données&#8230;<br />
La solution 2 est imbécile, complexe et peu performantes si vous avez plusieurs critères a rechercher&#8230;<br />
En sus, elle ne permet pas facilement de typer les informations, donc, vous aurez beaucoup de problématique de contrôle de qualité&#8230; et des performances catastrophiques</em></p>
<p><strong>DÉMONSTRATION</strong></p>
<p><strong>Partons d&rsquo;une table d&rsquo;animaux :</strong></p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> T_ANIMAL_ANM<br />
<span style="color: #66cc66;">&#40;</span>ANM_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span><br />
&nbsp;ANM_DATA &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">CHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8000</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #993333; font-weight: bold;">GO</span><br />
<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_ANIMAL_ANM <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Mytilus Edulis'</span><span style="color: #66cc66;">&#41;</span></div></div>
<p><strong></strong><br />
<strong>█ █ █ 1ere solution : une seule table pour toute une même famille :</strong></p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> T_MOLUSQUE_MSQ<br />
<span style="color: #66cc66;">&#40;</span>ANM_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> T_ANIMAL_ANM <span style="color: #66cc66;">&#40;</span>ANM_ID<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;MSQ_CARAPACE &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;MSQ_SYMETRIE &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;MSQ_COULEUR &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;MSQ_DIAMETRE_MM &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FLOAT</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p><strong></strong><br />
<strong>█ █ █ 2e solution (pour toutes familles), des tables &laquo;&nbsp;génériques&nbsp;&raquo; :</strong></p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> T_CARATERISTIQUE_CRT<br />
<span style="color: #66cc66;">&#40;</span>CRT_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span><br />
&nbsp;CRT_LIBELLE &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">256</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> T_VALEUR_VLR<br />
<span style="color: #66cc66;">&#40;</span>ANM_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> T_ANIMAL_ANM <span style="color: #66cc66;">&#40;</span>ANM_ID<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;CRT_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> T_CARATERISTIQUE_CRT<span style="color: #66cc66;">&#40;</span>CRT_ID<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;VLR_VALEUR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">256</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp;<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>ANM_ID<span style="color: #66cc66;">,</span> CRT_ID<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p>Ajoutons les caractéristiques identiques à celle de la solution 1</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">111</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Carapace'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">222</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Symétrie'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">333</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Couleur'</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">444</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Diamètre mm'</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p><strong></strong><br />
<strong>█ █ █ Voici maintenant les insertions :</strong></p>
<p><strong>Pour la solution 1 :</strong></p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_MOLUSQUE_MSQ <span style="color: #66cc66;">&#40;</span>ANM_ID<span style="color: #66cc66;">,</span> MSQ_CARAPACE<span style="color: #66cc66;">,</span> MSQ_SYMETRIE<span style="color: #66cc66;">,</span> MSQ_COULEUR<span style="color: #66cc66;">,</span> MSQ_DIAMETRE_MM<span style="color: #66cc66;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> &nbsp; &nbsp; &nbsp;<span style="color: #ff0000;">'Creatine'</span><span style="color: #66cc66;">,</span> &nbsp; <span style="color: #ff0000;">'Mono'</span><span style="color: #66cc66;">,</span> &nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">'Bleu'</span><span style="color: #66cc66;">,</span> &nbsp; &nbsp; &nbsp;<span style="color: #ff0000;">'82.5'</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Notez que nous n&rsquo;avons fait qu&rsquo;<strong>une seule requête</strong> d&rsquo;insertion avec correspondance caractéristique / valeur et typage des données</p>
<p><strong>Pour la solution 2 :</strong></p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_VALEUR_VLR <br />
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> CRT_ID<span style="color: #66cc66;">,</span> &nbsp; &nbsp;<span style="color: #ff0000;">'Creatine'</span> <span style="color: #993333; font-weight: bold;">FROM</span> T_CARATERISTIQUE_CRT <br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Carapace'</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_VALEUR_VLR <br />
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> CRT_ID<span style="color: #66cc66;">,</span> &nbsp; &nbsp;<span style="color: #ff0000;">'Mono'</span> &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> T_CARATERISTIQUE_CRT <br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Symétrie'</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_VALEUR_VLR <br />
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> CRT_ID<span style="color: #66cc66;">,</span> &nbsp; &nbsp;<span style="color: #ff0000;">'Bleu'</span> &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> T_CARATERISTIQUE_CRT <br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Couleur'</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_VALEUR_VLR <br />
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> CRT_ID<span style="color: #66cc66;">,</span> &nbsp; &nbsp;<span style="color: #ff0000;">'82,5'</span> &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> T_CARATERISTIQUE_CRT <br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Diamètre mm'</span>;</div></div>
<p>Pour stocker les mêmes informations, nous avons fait <strong>4 requêtes</strong> au lieu d&rsquo;une seule&#8230;.</p>
<p><strong>█ Comparons maintenant le coût des 2 solutions au niveau de l&rsquo;insertion :</strong></p>
<p><a href="http://blog.developpez.com/sqlpro/files/2018/08/Requetes-insertion-comparaison-couts.jpg"><img src="http://blog.developpez.com/sqlpro/files/2018/08/Requetes-insertion-comparaison-couts.jpg" alt="Comparaison des plans de requêtes pour l&#039;insertion" width="1190" height="897" class="alignnone size-full wp-image-857" /></a></p>
<p>Y&rsquo;a pas à tortiller 4 requêtes coutant deux fois plus cher qu&rsquo;une seule et unique requête cela est donc <strong>8 fois plus couteux</strong>&#8230;</p>
<p><strong>█ █ █ Voyons maintenant la facilité de requêtage :</strong></p>
<p>interrogation multicritères ET avec solution 1</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; T_ANIMAL_ANM <span style="color: #993333; font-weight: bold;">AS</span> A<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_MOLUSQUE_MSQ <span style="color: #993333; font-weight: bold;">AS</span> M<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> A<span style="color: #66cc66;">.</span>ANM_ID <span style="color: #66cc66;">=</span> M<span style="color: #66cc66;">.</span>ANM_ID<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;MSQ_CARAPACE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Creatine'</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;MSQ_SYMETRIE <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'Mono'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Double'</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;MSQ_COULEUR <span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #ff0000;">'Bleu%'</span> <span style="color: #808080; font-style: italic;">--&gt; peut être Bleue, Bleu-marine...</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;MSQ_DIAMETRE_MM <span style="color: #993333; font-weight: bold;">BETWEEN</span> <span style="color: #cc66cc;">75</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #cc66cc;">92</span>;</div></div>
<p>la requête fait <strong>8 lignes et 1 jointure</strong>. Elle en fera une de plus pour chaque critère supplémentaire avec juste quelques chose à rajouter à la clause WHERE&#8230;</p>
<p>interrogation multicritères ET avec solution 2</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span><br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; T_ANIMAL_ANM <span style="color: #993333; font-weight: bold;">AS</span> A<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_VALEUR_VLR <span style="color: #993333; font-weight: bold;">AS</span> V1 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> A<span style="color: #66cc66;">.</span>ANM_ID <span style="color: #66cc66;">=</span> V1<span style="color: #66cc66;">.</span>ANM_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">AS</span> C1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> V1<span style="color: #66cc66;">.</span>CRT_ID <span style="color: #66cc66;">=</span> C1<span style="color: #66cc66;">.</span>CRT_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_VALEUR_VLR <span style="color: #993333; font-weight: bold;">AS</span> V2 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> A<span style="color: #66cc66;">.</span>ANM_ID <span style="color: #66cc66;">=</span> V2<span style="color: #66cc66;">.</span>ANM_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">AS</span> C2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> V2<span style="color: #66cc66;">.</span>CRT_ID <span style="color: #66cc66;">=</span> C2<span style="color: #66cc66;">.</span>CRT_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_VALEUR_VLR <span style="color: #993333; font-weight: bold;">AS</span> V3 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> A<span style="color: #66cc66;">.</span>ANM_ID <span style="color: #66cc66;">=</span> V3<span style="color: #66cc66;">.</span>ANM_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">AS</span> C3<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> V3<span style="color: #66cc66;">.</span>CRT_ID <span style="color: #66cc66;">=</span> C3<span style="color: #66cc66;">.</span>CRT_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_VALEUR_VLR <span style="color: #993333; font-weight: bold;">AS</span> V4 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> A<span style="color: #66cc66;">.</span>ANM_ID <span style="color: #66cc66;">=</span> V4<span style="color: #66cc66;">.</span>ANM_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> T_CARATERISTIQUE_CRT <span style="color: #993333; font-weight: bold;">AS</span> C4<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> V4<span style="color: #66cc66;">.</span>CRT_ID <span style="color: #66cc66;">=</span> C4<span style="color: #66cc66;">.</span>CRT_ID<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;C1<span style="color: #66cc66;">.</span>CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Carapace'</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;V1<span style="color: #66cc66;">.</span>VLR_VALEUR <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Creatine'</span> <br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;C2<span style="color: #66cc66;">.</span>CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Symétrie'</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;V2<span style="color: #66cc66;">.</span>VLR_VALEUR <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'Mono'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Double'</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;C3<span style="color: #66cc66;">.</span>CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Couleur'</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;V3<span style="color: #66cc66;">.</span>VLR_VALEUR <span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #ff0000;">'Bleu%'</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;C4<span style="color: #66cc66;">.</span>CRT_LIBELLE <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Diamètre mm'</span><br />
&nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;V4<span style="color: #66cc66;">.</span>VLR_VALEUR <span style="color: #993333; font-weight: bold;">BETWEEN</span> <span style="color: #ff0000;">'75'</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">'92'</span></div></div>
<p>La requête fait <strong>26 lignes avec 8 jointures</strong>&#8230; Il faudra rajouter 6 lignes à chaque critère supplémentaire, dont 4 dans la clause FROM et 2 dans le WHERE, et encore, on ne sait pas dans la clause SELECT à quelle caractéristique se réfère chacune des valeurs&#8230; Il faudrait aussi customiser la clause SELECT&#8230;</p>
<p>Y&rsquo;a pas à tortiller la solution 1 est bien plus simple en matière d’écriture&#8230;</p>
<p><strong>█ Quelles sont les performances des requêtes de recherches des deux solutions ?</strong></p>
<p><a href="http://blog.developpez.com/sqlpro/files/2018/08/Requetes-selection-comparaison-couts.jpg"><img src="http://blog.developpez.com/sqlpro/files/2018/08/Requetes-selection-comparaison-couts.jpg" alt="Comparaison des plans de requêtes pour l&#039;extraction" width="2251" height="389" class="alignnone size-full wp-image-859" /></a></p>
<p><strong>Évidemment la première solution est 4,5 fois moins couteuse&#8230;</strong></p>
<p>Mais il y a pire&#8230; J&rsquo;ai du mettre des chiffres en chaine de caractères pour le diamètre (AND  V4.VLR_VALEUR BETWEEN &rsquo;75&rsquo; AND &rsquo;92&rsquo;). Si je tente de les typer en entier ou réel (AND  V4.VLR_VALEUR BETWEEN 75 AND 92), cela provoque une erreur d&rsquo;exécution (SQL Server) :<br />
<em>Msg*245, Niveau*16, État*1, Ligne*75<br />
Échec de la conversion de la valeur varchar &lsquo;Creatine&rsquo; en type de données int.</em><br />
Logique car pour effectuer une comparaison avec une valeur numérique, il faut convertir la colonne en numérique, mais comme il y a autres chose que de purs nombres (chaines de caractères) cela se passe mal.<br />
Bref certaines requêtes seront impossible à faire !</p>
<p>Plus catastrophique encore&#8230; mettre des index ne servira quasiment à rien ! En effet un index sur une chaine de caractères n’ordonne pas les valeurs de la même façon que s&rsquo;il s&rsquo;agissait de nombre&#8230;</p>
<p>En sus rien n&rsquo;interdira à quelqu’un de saisir 8,2 au lieu de 8.2 (une virgule au lieu d&rsquo;une point) comme diamètre, dans ce modèle inepte, alors qu&rsquo;avec le bon modèle les types sont respectés&#8230;. Si tel était le cas, la valeur ne pourra pas être retrouvée !!! Il existe bien évidemment une solution pour contourner, un tout petit peu, ce modèle pourri, pour le typage. Il consiste à rajouter autant de tables de valeurs que de type&#8230; Mais il n&rsquo;est pas possible de rajouter des contraintes spécifique à chaque type (par exemple vérifier qu&rsquo;une pourcentage est bien entre 0 et 100 &#8211; notion de domaine SQL), ni, bien entendu, de rajouter des contraintes multicritères (une valeur dépendant d&rsquo;une autre) comme c&rsquo;est le cas par exemple de la chronologie des temporels de type &laquo;&nbsp;début&nbsp;&raquo; et &laquo;&nbsp;fin&nbsp;&raquo;.<br />
Et dans tous les cas, les requêtes seront encore plus complexes à élaborer et les performances encore plus lamentables&#8230;</p>
<p><strong>En guise de conclusion</strong></p>
<p>Nous vous avons démontré les performances lamentable et la complexité horrifiante d&rsquo;un tel modèle&#8230;.</p>
<li>Complexité d&rsquo;insertion des données</li>
<li>Mauvaise performances à l&rsquo;insertion des données</li>
<li>Complexité d&rsquo;écriture des recherches</li>
<li>Mauvaise performances pour la recherches de données</li>
<li>Impossibilité de typer finement (notion de domaine)</li>
<li>Impossibilité de placer des contraintes multicritères</li>
<li>Difficultés pour l&rsquo;indexation</li>
<p><strong></strong><br />
<strong></strong></p>
<p>Mais comment se fait-il que des internautes osent affirmer de pareilles stupidités ?</p>
<p>Il est amusant de voir que certains développeur incultes affirment n&rsquo;importe quoi, par ignorance, ou par bêtise, ne prenant même pas la peine de tester ce qu&rsquo;ils disent&#8230; Ensuite ces mêmes développeurs, sans aucune expérience, iront vous raconter que les SGBDR c&rsquo;est pas performant&#8230; Ils vous vendrons alors du NoSQL, ce qui, dans beaucoup de cas, sera pire encore !</p>
<p>Comme disent les américains : &laquo;&nbsp;garbage in, garbage out&nbsp;&raquo; qui peut se traduire si tu fais de la merde en entrée, tu auras de la merde en sortie ! Autrement dit, si le modèle de données est inepte, la qualité des données sera pourrie et les performances lamentables&#8230;</p>
<p><strong>Décortiquons d&rsquo;ailleurs les affirmations de l&rsquo;internate que nous avons cité :</strong><br />
&laquo;&nbsp;<em>tout dépend de votre SGBD (pas précisé..), mais dans tous les cas, il suffit de mettre des ID numérique pour que les requêtes soient optimisées. Créez vos tables avec des id uniques (sous Oracle on peux utiliser les séquences) et vous aurez des traitements optimisées au mieux&#8230; mais bon, je vous rassure, sous Oracle, même avec des clefs en Varchar, pour 600 enregistrements, y a aucun pb..</em>&nbsp;&raquo;</p>
<p><strong>Première affirmation stupide</strong> : &laquo;&nbsp;<em>tout dépend de votre SGBD (pas précisé..)</em>&nbsp;&raquo;<br />
Comme nous sommes dans un forum sur les SGBDR, sachez cher monsieur, que tout les SGBDR fonctionnent de la même façon. Certains allant plus vite que d&rsquo;autre (une Ferrari va généralement plus vite qu&rsquo;une Peugeot), certains avec plus de qualité que d&rsquo;autres (une Rolls-Royce est généralement de meilleure qualité qu&rsquo;une Dacia).</p>
<p><strong>Seconde affirmation stupide</strong> : &laquo;&nbsp;<em>il suffit de mettre des ID numérique pour que les requêtes soient optimisées</em>&nbsp;&raquo;<br />
Si c&rsquo;était le cas alors, pas besoin d&rsquo;index ni de contraintes&#8230; On se demande donc pourquoi les éditeurs de SGBDR font de tels effort en R&amp;D pour trouver de nouvelles formes d&rsquo;index toujours plus performant&#8230;  Et la plupart des informaticiens ignorent que les contraintes permettent de mieux optimiser les plans de requête&#8230; Hélas ceci est très rarement enseigné par les professeurs des universités et encore moins ceux des écoles d&rsquo;ingénieurs&#8230; (je le sais pertinemment puisque j&rsquo;en étais un&#8230;).</p>
<p><strong>Troisième affirmation stupide</strong> : &laquo;&nbsp;<em>mais bon, je vous rassure, sous Oracle, même avec des clefs en Varchar</em>&nbsp;&raquo;<br />
Et bien, non, plus une clef est longue en nombre d&rsquo;octets, plus ses performances décroissent. Pour avoir la même longueur qu&rsquo;un entier auto incrémenté il faudrait se limiter à 4 caractères&#8230; En sus certaines phénomènes apparaissent avec des clefs non numériques et en particulier pour des clefs littérales :
<li>distribution peu aléatoire (parce que concentrées sur les 26 lettres et 10 chiffres parmi les 256 caractères disponibles) induisant des statistiques d&rsquo;optimisation mal réparties (histogrammes erratiques)</li>
<li>extra-overhead lié à la gestion de la collation (sensibilité ou non à la casse, aux accents&#8230;)</li>
<li>façon de stocker physiquement les VARCHAR induisant des octets suplementaires et de la fragmentaion en cas d&rsquo;UPDATE</li>
<p><strong></strong><br />
<strong></strong></p>
<p><strong>Quatrième affirmation stupide</strong> : &laquo;&nbsp;<em>sous Oracle, même avec des clefs en Varchar, pour 600 enregistrements, y a aucun pb..</em>&nbsp;&raquo;<br />
Nous avons déjà dit précédemment que les clef littérales (VARCHAR) étaient une plaie&#8230; Mais ce qui ne va pas dans cette phrase est le terme &laquo;&nbsp;<strong>enregistrement</strong>&laquo;&nbsp;&#8230; Cet internaute sait-il au moins que les SGBDR ne travaillent pas avec des &laquo;&nbsp;enregistrement&nbsp;&raquo; propre aux bases de données de type &laquo;&nbsp;fichier&nbsp;&raquo; comme c&rsquo;était las cas dans les années 50 à 70 ? Les SGBDR structurent les lignes des tables dans des pages qui sont modifiées en mémoire et non pas directement sur le disque (notion physique d&rsquo;enregistrement). Les pages étant physiquement écrites de temps à autres quand il y en a suffisamment à écrire par un processus asynchrone travaillant en tâche de fond.</p>
<p>Bref voici q&rsquo;un internaute ne connaissant ni la modélisation des données ni les technologies des SGDB, vient donner des conseils stupides hélas parfois repris dans certaines applications&#8230;.</p>
<p><strong></strong><br />
<strong></strong></p>
<p><strong>CQFD</strong></p>
<p><strong></strong><br />
<strong></strong></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Une peste nommée NOLOCK&#8230; et comment l&#8217;éviter</title>
		<link>https://blog.developpez.com/sqlpro/p13181/langage-sql-norme/une-peste-nommee-nolock-et-comment-leviter</link>
		<comments>https://blog.developpez.com/sqlpro/p13181/langage-sql-norme/une-peste-nommee-nolock-et-comment-leviter#comments</comments>
		<pubDate>Sun, 08 Jul 2018 14:55:07 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[SQL Server 2014]]></category>
		<category><![CDATA[SQL Server 2016]]></category>
		<category><![CDATA[SQL Server 2017]]></category>
		<category><![CDATA[ISOLATION]]></category>
		<category><![CDATA[NOLOCK]]></category>
		<category><![CDATA[SNAPSHOT]]></category>
		<category><![CDATA[transaction]]></category>
		<category><![CDATA[verrou]]></category>
		<category><![CDATA[verrouilage]]></category>
		<category><![CDATA[verrous]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=818</guid>
		<description><![CDATA[L&#8217;utilisation du tag de table NOLOCK, hélas largement prisé par de nombreux développeurs, est, la plupart du temps, une absurdité conduisant à des résultats potentiellement faux. Est-il possible de faire autrement pour minimiser les blocages induit par les verrouillages dans SQL Server ? Réponse OUI ! À la suite de cette remarque : &#171;&#160;&#8230;je passe [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>L&rsquo;utilisation du tag de table NOLOCK, hélas largement prisé par de nombreux développeurs, est, la plupart du temps, une absurdité conduisant à des résultats potentiellement faux. Est-il possible de faire autrement pour minimiser les blocages induit par les verrouillages dans SQL Server ? Réponse OUI !<br />
<span id="more-818"></span><br />
À la suite de cette remarque :<br />
<em>&laquo;&nbsp;&#8230;je passe aussi sur le NOLOCK qui est une véritable connerie en production et donne des valeurs fausses !&nbsp;&raquo;</em><br />
Publiée ici :<br />
<a href="https://www.developpez.net/forums/d1870299/bases-donnees/ms-sql-server/developpement/utilisation-excessive-structure-conditionnelle-choix-multiples/#post10343427" rel="noopener" target="_blank"></a><br />
Mon interlocuteur me répondais :<br />
<em>&laquo;&nbsp;Merci pour cette précision. Comme vous abordez le sujet du NOLOCK effectivement j&rsquo;ai constaté certaines fois en production on avait des valeurs totalement erronées, mais je n&rsquo;arrivais pas à me l&rsquo;expliquer. J&rsquo;ai maintenant une piste et je vais creuser du côté du NOLOCK que nous utilisons beaucoup en production sur une base de données CRM 2013. Aussi par quoi pouvons nous remplacer le NOLOCK ??&nbsp;&raquo;</em></p>
<p>Je lui donnais donc l&rsquo;explication suivante&#8230;<br />
<strong><br />
Le &laquo;&nbsp;NOLOCK&nbsp;&raquo; peut parfaitement se remplacer par le niveau d&rsquo;isolation SNAPSHOT</strong> par exemple&#8230;</p>
<p>NOLOCK ne signifie pas &laquo;&nbsp;<em>je ne pose pas de verrou</em>&laquo;&nbsp;, mais plus précisément : &laquo;&nbsp;<em>j&rsquo;ignore qu&rsquo;il y a des verrous et je lit ce que je peut</em>&nbsp;&raquo; (ceci est plus connu dans la littérature professionnelle sous le nom de <em><strong>lecture dans le chaos</strong></em>&#8230;). Vous pouvez donc lire plusieurs fois les mêmes données ou encore ne pas lire certaines.</p>
<p><strong>Quid du mode SNAPSHOT ?</strong></p>
<p>SNAPSHOT fait du verrouillage optimiste pour les lectures. Par défaut SQL Server fait du verrouillage pessimiste, c&rsquo;est à dire que les lectures posent des verrous qui permettent d&rsquo;autres lectures concurrentes (verrous partagés, mode &laquo;&nbsp;SHARE&nbsp;&raquo;), mais empêchent les écritures des autres utilisateurs. Conceptuellement, le verrouillage optimiste (donc via le mode d’isolation SNAPSHOT) fait une copie (si besoin) des données avant de permettre leurs lectures. Comme vous travaillez sur une copie, les utilisateurs concurrent peuvent modifier les vraies ligne sans que cela vous concerne. Bien entendu il peut toujours y avoir des conflits, mais cela réduit considérablement le nombre de verrous bloquants tout en gardant l&rsquo;intégrité et la consistante de la base, ce qui n&rsquo;est pas du tout le cas du NOLOCK.</p>
<p><strong>Alors, à quoi sert le NOLOCK ? </strong></p>
<p>Cela peut servir pour certains cas ou l&rsquo;on désire des résultats dont on se fout de l&rsquo;intégrité ou de la précision. Souvent dans le domaine de la statistique.<br />
par exemple si vous voulez savoir combien les français ont d&rsquo;enfant par foyer et scrutez donc, pour ce faire, une table de 60 millions de lignes (population française), je ne suis pas sûr que dans un camembert représentant la chose, on fasse la distinction des quelques pixels de l&rsquo;imprécision de la 6e décimale du résultat liées à quelques mauvaises lectures de lignes !<br />
On utilise d&rsquo;ailleurs très souvent le NOLOCK pour des tâches d&rsquo;administration systèmes dans SQL Server afin d&rsquo;éviter tout blocage au risque de perdre quelques lignes, ce qui n&rsquo;a pas toujours une importance capitale lorsque l&rsquo;on veut remonter quelques informations concernant les 20% de requêtes les moins performantes !</p>
<p><strong>Mais alors, le SNAPSHOT fait la même chose en mieux ? </strong></p>
<p>Oui et non&#8230; Certes il permet de garantir l&rsquo;intégrité, la consistance, etc&#8230; mais son mécanisme est plus lourd (un peu moins rapide) et consomme des ressources pour générer les copies (SNAPSHOT). Rassurez-vous il est assez malin pour ne faire ces copies qui s&rsquo;il a besoin de les faire&#8230; En d&rsquo;autres termes si aucun utilisateur concurrent veut faire des modif sur le jeu de lignes que vous manipulez en mode SNAPSHOT, aucune copie ne sera générée. Mais si, lorsque vous avez démarré une lecture en mode SNAPSHOT, un utilisateur concurrent veut modifier des lignes, et bien la copie sera réalisée au cours de votre lecture sans que vous vous en aperceviez&#8230; En quelque sorte le système fonctionne à l&rsquo;envers&#8230; Bien évidemment il faut un espace de stockage pour ces copies et c&rsquo;est la base tempdb qui s&rsquo;y colle. Il faut donc, la dimensionner correctement&#8230;<br />
Tiens, à nouveau un travail de DBA !</p>
<p><strong>Des conflits ! Quels conflits ?</strong></p>
<p>J&rsquo;ai précédemment parlé de conflits possible avec l&rsquo;utilisation du mode SNAPSHOT. En effet, si vous voulez modifier des données lors d&rsquo;une transaction en mode d’isolation SNAPSHOT, c&rsquo;est possible, mais ces modifications seront faites sur la copie, et non sur la base originale, et seront reportées sur la base originale au moment du COMMIT. Deux hypothèses se font alors jour :<br />
■ soit aucune ligne visée par vos modifications faites en mode SNAPSHOT n&rsquo;a été modifié dans une autre session directement sur la base, alors la mise à jour est appliquée.<br />
Ou alors :<br />
■ s&rsquo;il existe au moins une ligne qui a été modifiée par une autre session entre temps sur la base originale, alors vos modifications ne pourront être appliquées aux données originales et vont êtres abandonnées.<br />
Dans ce dernier cas vous obtiendrez une message d&rsquo;erreur (3960) assez abscons, qui indique :<br />
<em>&laquo;&nbsp;La transaction d&rsquo;isolement d&rsquo;instantané a été abandonnée en raison d&rsquo;un conflit de mise à jour. &#8230;&nbsp;&raquo;</em></p>
<p>Notez qu&rsquo;il existe un autre tag plus intéressant que le NOLOCK&#8230;. Le <strong>READPAST</strong> !&#8230;  Qui fait presque la même chose, mais ignore tout ce qui est verrouillé !</p>
<p><strong>Les modes d&rsquo;isolation selon la norme SQL</strong></p>
<p>Sachez que le mode d’isolation SNAPSHOT ne fait pas partie de la norme SQL qui n&rsquo;autorise que les modes d&rsquo;isolation suivants :<br />
0 &#8211; READ UNCOMMITTED : lecture des données invalides (non &laquo;&nbsp;committées&nbsp;&raquo;)<br />
1 &#8211; READ COMMITTED : lecture de données valides (ce qui n&rsquo;empêche pas certaines anomalies transactionnelles comme la lecture non répétable, ou l&rsquo;apparition de lignes fantômes)<br />
2 &#8211; REPEATABLE READ : lecture répétable de données (ce qui n&rsquo;empêche pas certaines anomalies transactionnelles comme l&rsquo;apparition de lignes fantômes)<br />
3 &#8211; SERIALIZABLE : lecture en mode série (aucun accès concurrent aux tables lors des mises à jour, ce qui empêche toute anomalies)<br />
Évidemment plus on monte le niveau d’isolation, plus le verrouillage est important et moins les accès concurrents peuvent travailler.<br />
La norme SQL considère que les manipulation des données doivent porter sur des valeurs &laquo;&nbsp;vivantes&nbsp;&raquo;. Hors, en utilisant le mode SNAPSHOT et son versionnement des lignes, ont est appelé à lire potentiellement des valeurs antérieurs des données, ce n&rsquo;est donc pas une lecture de l&rsquo;état actuel des valeurs dans la base&#8230;</p>
<p>Pour informations, des SGBRD comme Oracle, ou PostGreSQL fonctionnent nativement en mode d&rsquo;isolation SNAPSHOT, autrement dit utilisent systématiquement le verrouillage optimiste et ne savent pas faire autres choses (verrouillage pessimiste en particulier) voir ne savent même pas utiliser certains autres niveau d&rsquo;isolation. Par exemple PostGreSQL ne permet pas de faires des transaction en mode READ UNCOMMITTED et Oracle ne permettent pas d&rsquo;utiliser le niveau d&rsquo;isolation REPEATABLE READ&#8230;</p>
<p><strong>Activer le mode s&rsquo;isolation SNAPSHOT</strong></p>
<p>Pour permettre ce mode d&rsquo;isolation, vous devez d&rsquo;abord autoriser la base à utiliser le mode SNAPSHOT. Ce paramétrage est à deux niveaux :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ALTER DATABASE { CURRENT | nom_base } SET ALLOW_SNAPSHOT_ISOLATION ON;</div></div>
<p>permet d&rsquo;utiliser à tout moment le mode d’isolation SNAPSHOT qui doit être introduit préalablement par la commande SET TRANSACTION ISOLATION SNAPSHOT ou par un tag de table (SNAPSHOT)<br />
&#8230; et :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ALTER DATABASE { CURRENT | nom_base } SET READ_COMMITTED_SNAPSHOT ON;</div></div>
<p>qui place d&rsquo;office toutes les lectures en mode SNAPSHOT (comme le fait Oracle ou PostGreSQL);<br />
<strong>ATTENTION</strong> : pour assurer le versionnement des lignes, SQL Server rajoute à toutes les lignes de toutes les tables une information de version qui est codé sur 14 octets. Ceci peut prendre du temps à mettre en œuvre, en particulier sur de grosses bases.<br />
<strong></p>
<p>Appendice :</strong></p>
<p>Pour une démonstration des effets du NOLOCK : <a href="http://mssqlserver.fr/les-dangers-du-nolock/" rel="noopener" target="_blank">http://mssqlserver.fr/les-dangers-du-nolock/</a></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comparer deux requêtes aux résultats identiques</title>
		<link>https://blog.developpez.com/sqlpro/p13180/langage-sql-norme/comparer-deux-requetes-aux-resultats-identiques</link>
		<comments>https://blog.developpez.com/sqlpro/p13180/langage-sql-norme/comparer-deux-requetes-aux-resultats-identiques#comments</comments>
		<pubDate>Mon, 28 May 2018 07:25:44 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=814</guid>
		<description><![CDATA[Comment savoir si deux requêtes donnent le même résultat ? Il suffit d&#8217;une simple équation ensembliste pour ce faire. Sachant que la requête 1 donne comme résultat l&#8217;ensemble A et que la requête 2 donne comme résultat l&#8217;ensemble B, prouver que ces deux requêtes donnent le même résultat, nécessite d&#8217;appliquer l&#8217;équation : A &#8211; B [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Comment savoir si deux requêtes donnent le même résultat ?</p>
<p>Il suffit d&rsquo;une simple équation ensembliste pour ce faire. Sachant que la requête 1 donne comme résultat l&rsquo;ensemble A et que la requête 2 donne comme résultat l&rsquo;ensemble B, prouver que ces deux requêtes donnent le même résultat, nécessite d&rsquo;appliquer l&rsquo;équation :</p>
<p><strong>A &#8211; B U B &#8211; A = Ø</strong><br />
<span id="more-814"></span></p>
<p>Autrement dit que l&rsquo;union de la soustraction des éléments de B à l&rsquo;ensemble A et de la soustraction des éléments de A à l&rsquo;ensemble B ne donne aucun résultat (ensemble vide).</p>
<p>Ceci s&rsquo;exprime en SQL de la sorte :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">WITH<br />
TA AS (SELECT ....), -- requête 1<br />
TB AS (SELECT ....) &nbsp;-- requête 2<br />
SELECT * FROM TA<br />
EXCEPT<br />
SELECT * FROM TB<br />
UNION ALL<br />
SELECT * FROM TB<br />
EXCEPT<br />
SELECT * FROM TA;</div></div>
<p>Ne donne aucun résultat&#8230; CQFD</p>
<p>PS : pour oracle utilisez MINUS au lieu de EXCEPT&#8230;.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server 2017 comparatif performances Linux vs Windows</title>
		<link>https://blog.developpez.com/sqlpro/p13177/langage-sql-norme/sql-server-2017-comparatif-performances-linux-vs-windows</link>
		<comments>https://blog.developpez.com/sqlpro/p13177/langage-sql-norme/sql-server-2017-comparatif-performances-linux-vs-windows#comments</comments>
		<pubDate>Tue, 27 Mar 2018 09:38:20 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=810</guid>
		<description><![CDATA[Le but de cet article est de comparer les performances de Microsoft SQL Server 2017 sous Linux par rapport à Windows. Il a été élaboré sur des machines physiques strictement identiques pour ôter tout biais lié a l’utilisation de machines virtuelles. Vous trouverez les détails de cet article dans le fichier pdf suivant : sqlpro.developpez.com/article/sql_server_2017_linux_vs_windows/Benchmark_SQL_Server_2017_Linux_vs_Windows.pdf [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le but de cet article est de comparer les performances de Microsoft SQL Server 2017 sous Linux par rapport à Windows. Il a été élaboré sur des machines physiques strictement identiques pour ôter tout biais lié a l’utilisation de machines virtuelles.<br />
<span id="more-810"></span></p>
<p>Vous trouverez les détails de cet article dans le fichier pdf suivant :<br />
<a href="http://sqlpro.developpez.com/article/sql_server_2017_linux_vs_windows/Benchmark_SQL_Server_2017_Linux_vs_Windows.pdf" title="Comparatif des performances SQL Server 2017 Linux vs Windows">sqlpro.developpez.com/article/sql_server_2017_linux_vs_windows/Benchmark_SQL_Server_2017_Linux_vs_Windows.pdf</a></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>BENCHMARK SIG : PostGreSQL vs MS SQL Server</title>
		<link>https://blog.developpez.com/sqlpro/p13148/langage-sql-norme/755</link>
		<comments>https://blog.developpez.com/sqlpro/p13148/langage-sql-norme/755#comments</comments>
		<pubDate>Mon, 01 May 2017 14:54:34 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[PostGreSQL]]></category>
		<category><![CDATA[SQL Server 2016]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=755</guid>
		<description><![CDATA[La présent article compare les performances de requêtes basiques du système d&#8217;information géographique de PostGreSQL (v 9.6.1) et de SQL Server (version 2016). Comparaison des performances de SIG PostGreSQL/PostGIS vs SQL Server Spatial]]></description>
				<content:encoded><![CDATA[<p>La présent article compare les performances de requêtes basiques du système d&rsquo;information géographique de PostGreSQL (v 9.6.1) et de SQL Server (version 2016).</p>
<p><a href="http://g-ernaelsten.developpez.com/tutoriels/comparatif-sig-et-performances/" title="BENCHMARK SIG : PostGreSQL vs MS SQL Server" target="_blank">Comparaison des performances de SIG<br />
PostGreSQL/PostGIS vs SQL Server Spatial</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Les tables temporelles avec SQL Server (présentation)</title>
		<link>https://blog.developpez.com/sqlpro/p13141/langage-sql-norme/les-tables-temporelles-avec-sql-server-presentation</link>
		<comments>https://blog.developpez.com/sqlpro/p13141/langage-sql-norme/les-tables-temporelles-avec-sql-server-presentation#comments</comments>
		<pubDate>Wed, 25 Jan 2017 14:00:36 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[SQL Server 2016]]></category>
		<category><![CDATA[historisation]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[SQL server]]></category>
		<category><![CDATA[tables temporelles]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=751</guid>
		<description><![CDATA[Arrivée avec la norme SQL 2011, le concept de tables temporelles permet une historisation automatique des données et propose des opérateurs temporels pour &#171;&#160;voir&#160;&#187; vos données telles qu&#8217;elles étaient à un point ou une période du temps passé. Paradoxe : plus besoin de faire des sauvegardes ! Cette présentation montré au Microsoft Cloud Summit 2017 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Arrivée avec la norme SQL 2011, le concept de tables temporelles permet une historisation automatique des données et propose des opérateurs temporels pour &laquo;&nbsp;voir&nbsp;&raquo; vos données telles qu&rsquo;elles étaient à un point ou une période du temps passé. Paradoxe : plus besoin de faire des sauvegardes ! Cette présentation montré au Microsoft Cloud Summit 2017 à paris le 24 janvier 2017, vous montre l&rsquo;essentiel sur le sujet, avec SQL Server 2016 et est assortie de nombreux exemples.<br />
<span id="more-751"></span></p>
<p>La présentation PowerPoint sous forme PDF est téléchargeable ici : <a href="http://mssqlserver.fr/wp-content/uploads/2017/01/MSCloudSummit2017-SQL-et-les-tables-temporelles-Commentaires.pdf" title="SQL Server et les tables temporelles" target="_blank">SQL Server et les tables temporelles</a><br />
<strong><br />
Les exemples l&rsquo;accompagnant, sont téléchargeable ici :</strong></p>
<p><a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-001-table-temporelles-sans-historique.txt" target="_blank">DEMO 001 &#8211; table temporelles sans historique (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-002-table-temporelles-avec-historique.txt" target="_blank">DEMO 002 &#8211; table temporelles avec historique (fichier SQL)</a><br />
<a href="DEMO 003 – stockage (fichier SQL)" target="_blank">DEMO 003 &#8211; stockage (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-004-R%C3%A9cup%C3%A9ration.txt" target="_blank">DEMO 004 &#8211; Récupération (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-005-Purge.txt" target="_blank">DEMO 005 &#8211; Purge (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-005b-Purge-m%C3%A9tadonn%C3%A9es-blocage.txt" target="_blank">DEMO 005b &#8211; Purge métadonnées blocage (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-006-interrogation.txt" target="_blank">DEMO 006 &#8211; interrogation (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-007-In-Memory.txthttp://" target="_blank">DEMO 007 &#8211; In Memory (fichier SQL)</a><br />
<a href="http://mssqlserver.fr/wp-content/uploads/2017/01/DEMO-ANNEXE-temporal-tables.txt" target="_blank">DEMO ANNEXE temporal tables (fichier SQL)</a></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Most &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
<div id="attachment_590" style="width: 548px" class="wp-caption alignnone"><a href="http://blog.developpez.com/sqlpro/files/2015/09/Couverture-livre-SQL-server-Eyrolles.jpg"><img src="http://blog.developpez.com/sqlpro/files/2015/09/Couverture-livre-SQL-server-Eyrolles.jpg" alt="Développez et administrez pour la performance avec SQL Server 2014" width="538" height="652" class="size-full wp-image-590" /></a><p class="wp-caption-text">Développez et administrez pour la performance avec SQL Server 2014</p></div>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LIKE &#8216;%mot%&#8217; ou les index rotatifs&#8230;.</title>
		<link>https://blog.developpez.com/sqlpro/p13123/langage-sql-norme/like-mot-ou-les-index-rotatifs</link>
		<comments>https://blog.developpez.com/sqlpro/p13123/langage-sql-norme/like-mot-ou-les-index-rotatifs#comments</comments>
		<pubDate>Thu, 05 Jan 2017 20:01:44 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[SQL Server 2014]]></category>
		<category><![CDATA[SQL Server 2016]]></category>
		<category><![CDATA[index]]></category>
		<category><![CDATA[joker]]></category>
		<category><![CDATA[LIKE]]></category>
		<category><![CDATA[recherche]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=687</guid>
		<description><![CDATA[Qui n&#8217;a jamais rêvé d&#8217;obtenir des performances pour rechercher des mots partiels contenus dans d&#8217;autres mots, comme par exemple tous les mots contenant &#171;&#160;bolo&#160;&#187; ? Dans un dictionnaire de 128 918 mots, une telle recherche met moins de 50 millisecondes à l&#8217;aide des index rotatifs, contre ??? pour le LIKE &#8216;%bolo%&#8217;&#8230; Explications&#8230; diabolos, hyperboloïde, bolonaise, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Qui n&rsquo;a jamais rêvé d&rsquo;obtenir des performances pour rechercher des mots partiels contenus dans d&rsquo;autres mots, comme par exemple tous les mots contenant &laquo;&nbsp;bolo&nbsp;&raquo; ? Dans un dictionnaire de 128 918 mots, une telle recherche met moins de 50 millisecondes à l&rsquo;aide des index rotatifs, contre ??? pour le LIKE &lsquo;%bolo%&rsquo;&#8230; Explications&#8230;<br />
<span id="more-687"></span><br />
diabolos, hyperboloïde, bolonaise, bolomètre, diabolo, bolométriques, amphibologie, bolonais, paraboloïde, amphibologique, bolométrique&#8230; Tels sont les mots du dictionnaire LEXIQUE du CNRS contenant la chaine de caractères &laquo;&nbsp;boblo&nbsp;&raquo;.</p>
<p><strong>LE PROBLÈME</strong></p>
<p>Les index des bases de données relationnelles, de type BTree (arbre équilibrés) trient les chaines de caractères par rapport à l&rsquo;ordre orthographique des chaines de caractères au regard du classement des lettres de l&rsquo;alphabet et de la collation choisie, cette dernière pouvant être sensible ou non, à la casse, aux accents&#8230;. Du fait de cet ordre, il est donc possible de rechercher par intervalle comme c&rsquo;est le cas de la recherche d&rsquo;un mot commençant par&#8230; En effet, si nous recherchons les mots commençant par &laquo;&nbsp;fass&nbsp;&raquo; ils sont regroupés les uns à la suite des autres dans l&rsquo;index, ce qui permet un accès immédiat et la solution est, par exemple la suivante :
<ol>
<ul>fasse</ul>
<ul>fassent</ul>
<ul>fasses</ul>
<ul>fassiez</ul>
<ul>fassions</ul>
</ol>
<p>Pour ce qui est des mots finissant par, l&rsquo;index ne nous est d&rsquo;aucune utilité, mais une astuce consiste à créer les mots inversés (par exemple à l&rsquo;aide d&rsquo;une colonne calculée), les indexer et rechercher par le même type de LIKE sur l&rsquo;inverse de la terminaison souhaitée. Par exemple, rechercher tous les mots se terminant par &laquo;&nbsp;aide&rsquo;, il suffit de faire la recherche suivante :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #ff0000;">'edia%'</span></div></div>
<p>et de renvoyer le mot correspondant !<br />
Bien entendu pour rechercher un mot commençant par&#8230; et finissant par&#8230;, il suffit de combiner les deux recherches !<br />
Un exemple est apporté par l&rsquo;extrait de requête suivant :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">WHERE</span> MOT_MOT <span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #ff0000;">'enta%'</span> <span style="color: #993333; font-weight: bold;">AND</span> MOT_INVERSE <span style="color: #993333; font-weight: bold;">LIKE</span> CONCAT<span style="color: #66cc66;">&#40;</span>REVERSE<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'aient'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%'</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>Mais comment être efficace lorsque l&rsquo;on recherche une chaine à l&rsquo;intérieur d&rsquo;un mot ? C&rsquo;est là qu&rsquo;intervient la notion d&rsquo;index &laquo;&nbsp;rotatif&nbsp;&raquo;&#8230;</p>
<p><strong>LE CONCEPT</strong></p>
<p><strong>Un index &laquo;&nbsp;rotatif&nbsp;&raquo;</strong> est en fait une liste de mots pour laquelle on supprime successivement la lettre du début à chaque tour, d&rsquo;où le nom d&rsquo;index &laquo;&nbsp;rotatif&nbsp;&raquo;.<br />
Par exemple le mot &laquo;&nbsp;locomotive&nbsp;&raquo; sera ainsi décliné :
<ol>
<ul>locomotive</ul>
<ul>ocomotive</ul>
<ul>comotive</ul>
<ul>omotive</ul>
<ul>motive</ul>
<ul>otive</ul>
<ul>tive</ul>
<ul>ive</ul>
<ul>ve</ul>
<ul>e</ul>
</ol>
<p>On numérote alors chaque rotation, y compris le mot racine dont par convention on attribuera l&rsquo;indice 0 comme niveau de rotation. Par exemple le &laquo;&nbsp;sous-mot&nbsp;&raquo; &laquo;&nbsp;motive&nbsp;&raquo; aura un indice de rotation de 4 parce qu&rsquo;on lui aura retiré les 4 premières lettres.<br />
Une fois ces mots Ajoutés dans une table de mots, il suffit de les indexer et d&rsquo;ajouter une table des références croisées entre les mots racine et les rotations. La recherche peut désormais se faire via un LIKE &lsquo;mot%&rsquo; qui permet d&rsquo;exploiter l&rsquo;index ! Mais il faut ensuite remonter au mot racine par une jointure à l&rsquo;aide de la table des références croisées.</p>
<p><strong>LA MÉCANIQUE</strong></p>
<p>Afin de bien distinguer ces objets techniques de votre base, objets qui n&rsquo;ont rien à voir avec les objets fonctionnels de votre application, je vous conseille de créer un schéma SQL spécifique pour les y stocker logiquement</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> SCHEMA S_XRT;</div></div>
<p><strong>Les tables pour ce faire.</strong></p>
<p>Deux tables suffisent : la table des mots, et la table des références croisées.</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT<br />
<span style="color: #66cc66;">&#40;</span>MOT_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">IDENTITY</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span><br />
<span style="color: #808080; font-style: italic;">--&gt; doit être sensible aux accents mais pas à la casse ! Exemple maïs et </span><br />
<span style="color: #808080; font-style: italic;">-- &nbsp;mais, sur et sûr, retraite et retraité, congres et congrès !</span><br />
&nbsp;MOT_MOT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">COLLATE</span> French_BIN <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">UNIQUE</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT_ROTATION_MRT<br />
<span style="color: #66cc66;">&#40;</span>MRT_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">IDENTITY</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span><br />
<span style="color: #808080; font-style: italic;">-- pointe vers la rotation du mot</span><br />
&nbsp;MOT_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT <span style="color: #66cc66;">&#40;</span>MOT_ID<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
<span style="color: #808080; font-style: italic;">-- pointe vers la racine du mot</span><br />
&nbsp;MOT_ID_RACINE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT <span style="color: #66cc66;">&#40;</span>MOT_ID<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><br />
<span style="color: #808080; font-style: italic;">-- indice de rotation</span><br />
&nbsp;MRT_ROTATION &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TINYINT <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span><br />
&nbsp;<span style="color: #993333; font-weight: bold;">UNIQUE</span> <span style="color: #66cc66;">&#40;</span>MOT_ID<span style="color: #66cc66;">,</span> MOT_ID_RACINE<span style="color: #66cc66;">,</span> MRT_ROTATION<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p><strong>Les routines</strong></p>
<p>Une procédure va permettre d&rsquo;indexer un mot. En voici le code en Transact SQL :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">PROCEDURE</span> S_XRT<span style="color: #66cc66;">.</span>P_INDEXATION_ROTATIVE @MOT <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">AS</span><br />
<br />
<span style="color: #993333; font-weight: bold;">SET</span> NOCOUNT <span style="color: #993333; font-weight: bold;">ON</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">SET</span> @MOT <span style="color: #66cc66;">=</span> <span style="color: #993333; font-weight: bold;">LOWER</span><span style="color: #66cc66;">&#40;</span>LTRIM<span style="color: #66cc66;">&#40;</span>RTRIM<span style="color: #66cc66;">&#40;</span>@MOT<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">DECLARE</span> @L TINYINT <span style="color: #66cc66;">=</span> LEN<span style="color: #66cc66;">&#40;</span>@MOT<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> @ID_MOT <span style="color: #993333; font-weight: bold;">INT</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">DECLARE</span> @ROTATIONS <span style="color: #993333; font-weight: bold;">TABLE</span> <br />
<span style="color: #66cc66;">&#40;</span>MOT &nbsp; <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">COLLATE</span> French_BIN<span style="color: #66cc66;">,</span><br />
&nbsp;ROT &nbsp; TINYINT<span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #808080; font-style: italic;">-- calcul des rotations, racine comprise (0)</span><br />
<span style="color: #993333; font-weight: bold;">WITH</span> T <span style="color: #993333; font-weight: bold;">AS</span> <br />
<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> @MOT <span style="color: #993333; font-weight: bold;">AS</span> M<span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">AS</span> I<br />
&nbsp;<span style="color: #993333; font-weight: bold;">UNION</span> &nbsp;<span style="color: #993333; font-weight: bold;">ALL</span><br />
&nbsp;<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">RIGHT</span><span style="color: #66cc66;">&#40;</span>M<span style="color: #66cc66;">,</span> @L<span style="color: #66cc66;">-</span>I <span style="color: #66cc66;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> I <span style="color: #66cc66;">+</span> <span style="color: #cc66cc;">1</span><br />
&nbsp;<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; T<br />
&nbsp;<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;I <span style="color: #66cc66;">&lt;</span> @L <span style="color: #66cc66;">-</span> <span style="color: #cc66cc;">1</span><br />
<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> @ROTATIONS<br />
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> T;<br />
<br />
<span style="color: #808080; font-style: italic;">-- insertions des mots manquants</span><br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT<br />
<span style="color: #993333; font-weight: bold;">SELECT</span> MOT<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; @ROTATIONS<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;MOT <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> MOT_MOT<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; S_XRT<span style="color: #66cc66;">.</span>T_MOT<span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #808080; font-style: italic;">-- récupération de l'ID du mot racine</span><br />
<span style="color: #993333; font-weight: bold;">SELECT</span> @ID_MOT <span style="color: #66cc66;">=</span> MOT_ID<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; S_XRT<span style="color: #66cc66;">.</span>T_MOT<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;MOT_MOT <span style="color: #66cc66;">=</span> @MOT;<br />
<br />
<span style="color: #808080; font-style: italic;">-- insertions des rotations manquantes</span><br />
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT_ROTATION_MRT<br />
<span style="color: #993333; font-weight: bold;">SELECT</span> M<span style="color: #66cc66;">.</span>MOT_ID<span style="color: #66cc66;">,</span> @ID_MOT<span style="color: #66cc66;">,</span> R<span style="color: #66cc66;">.</span>ROT<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; @ROTATIONS <span style="color: #993333; font-weight: bold;">AS</span> R<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT <span style="color: #993333; font-weight: bold;">AS</span> M<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> R<span style="color: #66cc66;">.</span>MOT <span style="color: #66cc66;">=</span> M<span style="color: #66cc66;">.</span>MOT_MOT<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;<span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">EXISTS</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; S_XRT<span style="color: #66cc66;">.</span>T_MOT_ROTATION_MRT <span style="color: #993333; font-weight: bold;">AS</span> MR<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;MR<span style="color: #66cc66;">.</span>MOT_ID <span style="color: #66cc66;">=</span> M<span style="color: #66cc66;">.</span>MOT_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;MR<span style="color: #66cc66;">.</span>MOT_ID_RACINE <span style="color: #66cc66;">=</span> @ID_MOT<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">AND</span> &nbsp;MR<span style="color: #66cc66;">.</span>MRT_ROTATION <span style="color: #66cc66;">=</span> R<span style="color: #66cc66;">.</span>ROT<span style="color: #66cc66;">&#41;</span>;</div></div>
<p>Enfin, une fonction table constituée d&rsquo;une simple requête paramétrée, va permettre de retrouver les mots racine à partir des partiels :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">FUNCTION</span> S_XRT<span style="color: #66cc66;">.</span>F_SUPER_LIKE <span style="color: #66cc66;">&#40;</span>@MOT <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">RETURNS</span> <span style="color: #993333; font-weight: bold;">TABLE</span><br />
<span style="color: #993333; font-weight: bold;">AS</span><br />
<span style="color: #993333; font-weight: bold;">RETURN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> MR<span style="color: #66cc66;">.</span>MOT_ID<span style="color: #66cc66;">,</span> MR<span style="color: #66cc66;">.</span>MOT_MOT<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; S_XRT<span style="color: #66cc66;">.</span>T_MOT <span style="color: #993333; font-weight: bold;">AS</span> M<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #66cc66;">&#91;</span>S_XRT<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">.</span><span style="color: #66cc66;">&#91;</span>T_MOT_ROTATION_MRT<span style="color: #66cc66;">&#93;</span> <span style="color: #993333; font-weight: bold;">AS</span> R<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> M<span style="color: #66cc66;">.</span>MOT_ID <span style="color: #66cc66;">=</span> R<span style="color: #66cc66;">.</span>MOT_ID<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">JOIN</span> S_XRT<span style="color: #66cc66;">.</span>T_MOT <span style="color: #993333; font-weight: bold;">AS</span> MR<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">ON</span> R<span style="color: #66cc66;">.</span>MOT_ID_RACINE <span style="color: #66cc66;">=</span> MR<span style="color: #66cc66;">.</span>MOT_ID<br />
<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;M<span style="color: #66cc66;">.</span>MOT_MOT <span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #993333; font-weight: bold;">LOWER</span><span style="color: #66cc66;">&#40;</span>RTRIM<span style="color: #66cc66;">&#40;</span>LTRIM<span style="color: #66cc66;">&#40;</span>@MOT<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">+</span> <span style="color: #ff0000;">'%'</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p><strong>QUELQUES TESTS</strong></p>
<p>Nous sommes partis d&rsquo;une base contenant le dictionnaire LEXIQUE du CNRS, comportant 128 918 mots.<br />
Notre méthode pour les indexer tous a été d&rsquo;utiliser un curseur pour connaitre le temps moyen mis par la procédure d&rsquo;indexation. Ce traitement a été effectué sur une machine ayant les caractéristiques suivantes : 2 processeurs XEON, 48 cœurs , 128 Go de RAM, 8 disques SAS en RAID 10 avec SQL Server 2016.<br />
Le temps de traitement a été de 26 minutes et 21 secondes, soit, pour 128 918 mots, 12 ms par mot.<br />
Le traitement a généré  :<br />
*   376 567 entrées de mots dans la table S_XRT.T_MOT (représentant 24 Mo)<br />
* 1 168 547 lignes dans la table S_XRT.T_MOT_ROTATION_MRT (représentant 62 Mo)<br />
À noter qu&rsquo;après réindexation, on observe une diminution du volume des données : 22 et 57 Ko respectivement.</p>
<p>Voici le batch que nous avons utilisé (la table du dictionnaire LEXIQUE du CNRS est dbo.TS_MOT_MOT :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">DECLARE</span> @T DATETIME <span style="color: #66cc66;">=</span> GETDATE<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">DECLARE</span> C CURSOR <br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">LOCAL</span> FORWARD_ONLY STATIC READ_ONLY<br />
<span style="color: #993333; font-weight: bold;">FOR</span> <br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">SELECT</span> MOT_MOT <br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; dbo<span style="color: #66cc66;">.</span>TS_MOT_MOT<br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">WHERE</span> &nbsp;MOT_LONGUEUR <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">1</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">DECLARE</span> @MOT <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #66cc66;">&#41;</span>;<br />
<br />
<span style="color: #993333; font-weight: bold;">OPEN</span> C;<br />
<br />
FETCH C <span style="color: #993333; font-weight: bold;">INTO</span> @MOT;<br />
<br />
WHILE @@FETCH_STATUS <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">0</span><br />
<span style="color: #993333; font-weight: bold;">BEGIN</span><br />
<br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">EXEC</span> S_XRT<span style="color: #66cc66;">.</span>P_INDEXATION_ROTATIVE @MOT;<br />
&nbsp; &nbsp;FETCH C <span style="color: #993333; font-weight: bold;">INTO</span> @MOT;<br />
<br />
<span style="color: #993333; font-weight: bold;">END</span>;<br />
<br />
CLOSE C;<br />
<br />
DEALLOCATE C;<br />
<br />
<span style="color: #993333; font-weight: bold;">SELECT</span> DATEDIFF<span style="color: #66cc66;">&#40;</span>ms<span style="color: #66cc66;">,</span> @T<span style="color: #66cc66;">,</span> GETDATE<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p>L&rsquo;utilisation de la fonction table en ligne S_XRT.F_SUPER_LIKE, met en moyenne 50 ms quelques soit la racine cherchée si elle est constituée d&rsquo;au moins 3 caractères. Exemple :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> S_XRT<span style="color: #66cc66;">.</span>F_SUPER_LIKE<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'moti'</span><span style="color: #66cc66;">&#41;</span>;</div></div>
<p>Pour la pire des recherches, le système met moins d&rsquo;une seconde à trouver les 130 162 mots contenant la lettre e !</p>
<p>Pour comparaison, la recherche des mots comprenant les caractères &laquo;&nbsp;eta&nbsp;&raquo;, d&rsquo;une part directement dans le dictionnaire à l&rsquo;aide d&rsquo;un LIKE &lsquo;%eta%&rsquo; et d&rsquo;autres part dans l&rsquo;index rotatif donne les métriques suivantes :<br />
* Dictionnaire, LIKE&rsquo;%eta%&rsquo; : temps UC = 652 ms, temps écoulé = 430 ms.<br />
* Index rotatif, S_XRT.F_SUPER_LIKE (&lsquo;eta&rsquo;) : Temps UC = 265 ms, temps écoulé = 50 ms.</p>
<p>Paradoxalement les plans de requête ne reflètent pas vraiment cette différence. les couts des plans apparaissent ainsi :<br />
* Index rotatif, S_XRT.F_SUPER_LIKE (&lsquo;eta&rsquo;) : 3,79 (soit 86 % de l&rsquo;ensemble<br />
* Dictionnaire, LIKE&rsquo;%eta%&rsquo; : 0,61 (soit 14% de l&rsquo;ensemble)</p>
<div id="attachment_692" style="width: 635px" class="wp-caption alignnone"><a href="http://blog.developpez.com/sqlpro/files/2017/01/Fonction-SUPER-LIKE.jpg"><img src="http://blog.developpez.com/sqlpro/files/2017/01/Fonction-SUPER-LIKE-1024x132.jpg" alt="Plan de requête SQL Server utilisant une fonction table en ligne et l&#039;index rotatif" width="800" height="104" class="size-large wp-image-692" /></a><p class="wp-caption-text">Plan de requête SQL Server utilisant une fonction table en ligne et l&rsquo;index rotatif</p></div>
<div id="attachment_693" style="width: 223px" class="wp-caption alignnone"><a href="http://blog.developpez.com/sqlpro/files/2017/01/LIKE-direct.jpg"><img src="http://blog.developpez.com/sqlpro/files/2017/01/LIKE-direct.jpg" alt="Utilisation directe du LIKE &#039;%toto%&#039;" width="213" height="68" class="size-full wp-image-693" /></a><p class="wp-caption-text">Utilisation directe du LIKE &lsquo;%toto%&rsquo;</p></div>
<p><strong>UN PEU D&rsquo;ASTUCE</strong></p>
<p>Au fur et à mesure de son utilisation, les index rotatifs grandissent de moins en moins, car ils contiennent déjà des rotations utilisables pour d&rsquo;autres mots. On peut donc prévoir certaines manœuvres pour les rendre plus efficaces encore, comme le précalcul de certaines données, la compression des index ou encore l&rsquo;utilisation de vues matérialisées (ou indexées sur SQL Server).</p>
<p>À titre d&rsquo;exemple, nous avons obtenus la métrique suivante : temps UC = 63 ms, temps écoulé = 67 ms, à  l&rsquo;aide de l&rsquo;une de ces techniques !</p>
<p><strong>LE CODE * LE CODE * LE CODE * LE CODE * LE CODE * LE CODE * LE CODE * LE CODE * LE CODE</strong><br />
<a href="http://sqlpro.developpez.com/_fichierSQL/IndexRotatifs.txt" title="Fichier du code" target="_blank">Le code SQL</a></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
<div id="attachment_590" style="width: 548px" class="wp-caption alignnone"><a href="http://blog.developpez.com/sqlpro/files/2015/09/Couverture-livre-SQL-server-Eyrolles.jpg"><img src="http://blog.developpez.com/sqlpro/files/2015/09/Couverture-livre-SQL-server-Eyrolles.jpg" alt="Développez et administrez pour la performance avec SQL Server 2014" width="538" height="652" class="size-full wp-image-590" /></a><p class="wp-caption-text">Développez et administrez pour la performance avec SQL Server 2014</p></div>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Benchmark PostgreSQL vs SQL Server&#8230; comment biaiser !</title>
		<link>https://blog.developpez.com/sqlpro/p12959/langage-sql-norme/benchmark-postgresql-vs-sql-server-comment-biaiser</link>
		<comments>https://blog.developpez.com/sqlpro/p12959/langage-sql-norme/benchmark-postgresql-vs-sql-server-comment-biaiser#comments</comments>
		<pubDate>Tue, 17 Nov 2015 22:25:52 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[PostGreSQL]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[Benchmark]]></category>
		<category><![CDATA[comparaison]]></category>
		<category><![CDATA[SQL server]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=626</guid>
		<description><![CDATA[La mauvaise foi règne encore chez les aficionados de PostGreSQL&#8230; L&#8217;entreprise Red Hat, que je croyais sérieuse, à effectué un benchmark entre PostGreSQL et SQL Server stupéfiant de mauvaise foi&#8230; Voici mes remarques. À noter, ce comparatif porte sur une version payante de PostGreSQL ! On trouvera le benchmark dont je parle &#171;&#160;Comparing BenchmarkSQL Performance [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La mauvaise foi règne encore chez les aficionados de PostGreSQL&#8230; L&rsquo;entreprise Red Hat, que je croyais sérieuse, à effectué un benchmark entre PostGreSQL et SQL Server stupéfiant de mauvaise foi&#8230; Voici mes remarques. À noter, ce comparatif porte sur une version payante de PostGreSQL !<br />
<span id="more-626"></span><br />
On trouvera le benchmark dont je parle &laquo;&nbsp;Comparing BenchmarkSQL Performance on Red Hat® Enterprise Linux 5 to Windows Server Enterprise&nbsp;&raquo; à l&rsquo;URL :<br />
<a href="https://www.redhat.com/pdf/rhel/bmsql-postgres-sqlsrvr-v1.0-1.pdf" title="Comparing BenchmarkSQL Performance on Red Hat® Enterprise Linux 5 to Windows Server Enterprise" target="_blank">https://www.redhat.com/pdf/rhel/bmsql-postgres-sqlsrvr-v1.0-1.pdf</a></p>
<p>Passons sur le choix du benchmark : le TPC-C qui date de 1992 (soit 23 ans&#8230;) est constitué d&rsquo;une base de données qui comporte 9 tables et dont on peut trouver le détail à l&rsquo;URL :<br />
<a href="http://www.tpc.org/tpc_documents_current_versions/pdf/tpc-c_v5-11.pdf" title="Détail du benchmark TPC-C" target="_blank">http://www.tpc.org/tpc_documents_current_versions/pdf/tpc-c_v5-11.pdf</a>. Qui aujourd&rsquo;hui utilise en production une base composée au plus de 9 tables ? En revanche il existe un benchmark plus moderne, le TPC-E composé de 33 tables nettement plus réaliste !</p>
<p><strong>TUNING DES OS</strong></p>
<p>À la page 10 dudit benchmark on trouve le paragraphe <em>3.3.1 (Operating System)</em> qui montre comment à été optimisé Linux.</p>
<p><a href="http://blog.developpez.com/sqlpro/files/2015/11/PostGreSQL-vs-SQL-Server-OS-Tuning.jpg"><img src="http://blog.developpez.com/sqlpro/files/2015/11/PostGreSQL-vs-SQL-Server-OS-Tuning.jpg" alt="PostGreSQL vs SQL Server OS Tuning" width="829" height="621" class="alignnone size-full wp-image-630" /></a></p>
<p>On y voit clairement que <strong>seul l&rsquo;OS Linux a été optimisé</strong>. Quelles optimisations ont été faites pour Windows ? <strong>Aucune !</strong></p>
<p>Or il est bien évident qu&rsquo;une installation standard de Windows pour héberger SQL Server n&rsquo;est pas optimale sans certains réglages :<br />
&#8211; désactivation des services inutiles (ce qui a été fait pour Linux et pas pour Windows)<br />
&#8211; désactivation du système d&rsquo;économie d’énergie (qui n&rsquo;existe pas sous Linux.. pas écolo les linuxiens !)<br />
&#8211; activation de Turbo Boost<br />
&#8211; activation de l&rsquo;Instant File Initialization pour le service SQL Server<br />
&#8211; activation du Lock Page in Memory pour SQL Server<br />
&#8230;</p>
<p><strong>TUNING DES SGBDR</strong></p>
<p>À la page 11 figure le paragraphe 3.3.3 (Database) qui montre comment a été optimisé PostGreSQL.</p>
<p><a href="http://blog.developpez.com/sqlpro/files/2015/11/PostGreSQL-vs-SQL-Server-database-Tuning.jpg"><img src="http://blog.developpez.com/sqlpro/files/2015/11/PostGreSQL-vs-SQL-Server-database-Tuning.jpg" alt="PostGreSQL vs SQL Server database Tuning" width="819" height="563" class="alignnone size-full wp-image-631" /></a></p>
<p>On y voit clairement que <strong>seul PostGreSQL a été optimisé</strong>. Red Hat revendique même sa tromperie : &laquo;&nbsp;<em>&#8230;no specific SQL Server tuning was performed</em>&nbsp;&raquo; !</p>
<p>Or il est bien évident que plusieurs optimisations sont nécessaires :<br />
&#8211; la ventilation du stockage des fichiers de données de la base tempdb (objets temporaires) en autant de fichiers d&rsquo;égales longueur que de CPU (donc au moins 2);<br />
&#8211; le dimensionnement correct des fichiers de la base de données à 40 Go pour les données et 10 Go pour les transactions avec à nouveau au moins 2 fichiers pour les données<br />
&#8211; la limitation de la RAM utilisée par SQL Server à au moins 44 Go (max server memory);<br />
&#8211; la limitation du parallélisme des requêtes à 4 (du fait que le serveur présente 2 CPU Quad Core et 4 LUN par agrégats RAID) et hausse du seuil de déclenchement à 12 (cost threshold for parallelism);<br />
&#8211; le positionnement du paramètre &laquo;&nbsp;optimize for ad hoc workloads&nbsp;&raquo; à 1 sinon les plans de requête ne sont pas mis en cache !<br />
&#8211; l&rsquo;élévation du délai de report des écritures physique de données (checkpoint), paramètre &laquo;&nbsp;recovery interval&nbsp;&raquo;, à 60 minutes pour coller au paramètre &laquo;&nbsp;checkpoint_timeout &nbsp;&raquo; positionné à 1 heure dans PostGreSQL (un délai tout à fait anormal entre nous, car cela pourrait s&rsquo;avérer dangereux en production&#8230;)<br />
&#8230;</p>
<p><strong>POSTGRESQL PLUS</strong></p>
<p>Très discrètement, le document montre que la version testée de PostGreSQL n&rsquo;est pas la version gratuite Open Source, mais la version payante fabriquée par EntrepriseDB et nommée &laquo;&nbsp;PostGreSQL PLUS.<br />
Nous n&rsquo;avons pas pu obtenir le prix d&rsquo;une telle version directement sur le site d&rsquo;EntrepriseDB, mais <a href="https://assets.digitalmarketplace.service.gov.uk/documents/93566/5258173757784064-pricing-document.pdf" title="PostGreSQL PLUS prix des licences" target="_blank">sur un autre document, provenant probablement du gouvernement britannique</a> ce prix apparait être 3 265 £ par CPU (socket), soit environ 4 700 €&#8230;<br />
En comparaison, SQL Server 2008 R2 version Web, suffisante pour ce benchmark, coute 4 246,41&#8230;</p>
<p><strong>LES RÉSULTATS</strong></strong></p>
<p>Comme on s&rsquo;y attendait, avec un tel paramétrage, PostGreSQL bât haut la main SQL Server ! <em>haut la main ?</em> <strong>pas si sûr&#8230;</strong></p>
<p><a href="http://blog.developpez.com/sqlpro/files/2015/11/PostGreSQL-vs-SQL-Server-Resultats.jpg"><img src="http://blog.developpez.com/sqlpro/files/2015/11/PostGreSQL-vs-SQL-Server-Resultats.jpg" alt="PostGreSQL vs SQL Server Resultats" width="731" height="645" class="alignnone size-full wp-image-632" /></a></p>
<p>Il faut vraiment y aller à la loupe pour voir la différence. En mesurant après impression avec une règle, j&rsquo;ai constaté un écart relatif de 3 à 5 % mesuré sur les entrées 40 et 140 de l&rsquo;histogramme&#8230;</p>
<p>Bref, il est très probable qu&rsquo;avec les réglages manquants pour Windows et SQL Server, Red Hat n&rsquo;aurait jamais publié un tel benchmark tant il aurait été défavorable à PostGreSQL fût-il PLUS !</p>
<p>Ce qui me navre c&rsquo;est que je croyais naïvement que Red Hat était une entreprise sérieuse !</p>
<p>***</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Lister les bases système de SQL Server</title>
		<link>https://blog.developpez.com/sqlpro/p12856/langage-sql-norme/lister-les-bases-systeme-de-sql-server</link>
		<comments>https://blog.developpez.com/sqlpro/p12856/langage-sql-norme/lister-les-bases-systeme-de-sql-server#comments</comments>
		<pubDate>Fri, 27 Mar 2015 09:58:38 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[SQL Server 2014]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=560</guid>
		<description><![CDATA[Voici une requête permettant de lister toutes ls bases systèmes de MS SQL Server. SELECT name AS database_name, database_id, &#160; &#160; &#160; &#160;CAST&#40;CASE &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;WHEN name IN &#40;'master','model','msdb','tempdb'&#41; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; THEN 1 &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;WHEN is_distributor = [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Voici une requête permettant de lister toutes ls bases systèmes de MS SQL Server.<br />
<span id="more-560"></span></p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SELECT</span> name <span style="color: #993333; font-weight: bold;">AS</span> database_name<span style="color: #66cc66;">,</span> database_id<span style="color: #66cc66;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">CAST</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">CASE</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">WHEN</span> name <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'master'</span><span style="color: #66cc66;">,</span><span style="color: #ff0000;">'model'</span><span style="color: #66cc66;">,</span><span style="color: #ff0000;">'msdb'</span><span style="color: #66cc66;">,</span><span style="color: #ff0000;">'tempdb'</span><span style="color: #66cc66;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">THEN</span> <span style="color: #cc66cc;">1</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">WHEN</span> is_distributor <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">THEN</span> <span style="color: #cc66cc;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">ELSE</span> <span style="color: #cc66cc;">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">END</span> <span style="color: #993333; font-weight: bold;">AS</span> bit<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> system_database<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; sys<span style="color: #66cc66;">.</span><span style="color: #993333; font-weight: bold;">DATABASES</span>;</div></div>
<p><a href="http://www.eyrolles.com/Informatique/Livre/sql-server-2014-9782212135923"><strong>Le livre sur Microsoft SQL Server 2014 : <em>développez et administrez pour la performance</em> &#8211; éditions Eyrolles</strong></a></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Calcules de durée en jour avec des mois comptables  de 30 jours</title>
		<link>https://blog.developpez.com/sqlpro/p12855/langage-sql-norme/calcules-de-duree-en-jour-avec-des-mois-compatbels-de-30-jours</link>
		<comments>https://blog.developpez.com/sqlpro/p12855/langage-sql-norme/calcules-de-duree-en-jour-avec-des-mois-compatbels-de-30-jours#comments</comments>
		<pubDate>Mon, 23 Mar 2015 22:55:56 +0000</pubDate>
		<dc:creator><![CDATA[SQLpro]]></dc:creator>
				<category><![CDATA[Langage SQL (norme)]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[SQL Server 2000]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[SQL Server 2014]]></category>
		<category><![CDATA[30 jours]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[mois comptable]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/sqlpro/?p=556</guid>
		<description><![CDATA[À la suite d&#8217;une demande du forum, je me suis penché sur le calcul de durée en jour avec des mois comptables de 30 jours. Comme d&#8217;habitude il faut passer par une table de date ! La demande originale est postée ici : www.developpez.net/forums/d1508019/bases-donnees/ms-sql-server/developpement/ Nous sommes partit de la table suivante : CREATE TABLE T_DAT [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>À la suite d&rsquo;une demande du forum, je me suis penché sur le calcul de durée en jour avec des mois comptables de 30 jours. Comme d&rsquo;habitude il faut passer par une table de date !<br />
<span id="more-556"></span><br />
La demande originale est postée ici :<br />
<a href="www.developpez.net/forums/d1508019/bases-donnees/ms-sql-server/developpement/">www.developpez.net/forums/d1508019/bases-donnees/ms-sql-server/developpement/</a></p>
<p>Nous sommes partit de la table suivante :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> T_DAT<br />
<span style="color: #66cc66;">&#40;</span>DAT_DATE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">DATE</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span><br />
&nbsp;DAT_AN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #993333; font-weight: bold;">CAST</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">YEAR</span><span style="color: #66cc66;">&#40;</span>DAT_DATE<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #993333; font-weight: bold;">SMALLINT</span><span style="color: #66cc66;">&#41;</span> PERSISTED<span style="color: #66cc66;">,</span><br />
&nbsp;DAT_MOIS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #993333; font-weight: bold;">CAST</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">MONTH</span><span style="color: #66cc66;">&#40;</span>DAT_DATE<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> TINYINT<span style="color: #66cc66;">&#41;</span> PERSISTED<span style="color: #66cc66;">,</span><br />
&nbsp;DAT_JOUR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #993333; font-weight: bold;">CAST</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">DAY</span><span style="color: #66cc66;">&#40;</span>DAT_DATE<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> TINYINT<span style="color: #66cc66;">&#41;</span> &nbsp; PERSISTED<span style="color: #66cc66;">,</span><br />
&nbsp;DAT_NB_JOUR_FIN_MOIS &nbsp; &nbsp; TINYINT <span style="color: #66cc66;">,</span><br />
&nbsp;DAT_JOUR_FIN_MOIS &nbsp; &nbsp; &nbsp; &nbsp;TINYINT<br />
<span style="color: #66cc66;">&#41;</span>;</div></div>
<p>Que nous avons rempli avec les 3 requêtes suivantes :</p>
<div class="codecolorer-container sql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="sql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333; font-weight: bold;">SET</span> NOCOUNT <span style="color: #993333; font-weight: bold;">ON</span>;<br />
<span style="color: #993333; font-weight: bold;">DECLARE</span> @D <span style="color: #993333; font-weight: bold;">DATE</span><br />
<span style="color: #993333; font-weight: bold;">SET</span> @D <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'2000-01-01'</span><br />
WHILE @D <span style="color: #66cc66;">&lt;</span> <span style="color: #ff0000;">'2100-12-31'</span><br />
<span style="color: #993333; font-weight: bold;">BEGIN</span><br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> T_DAT <span style="color: #66cc66;">&#40;</span>DAT_DATE<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>@D<span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">SET</span> @D <span style="color: #66cc66;">=</span> DATEADD<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">DAY</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> @D<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">END</span>;<br />
<span style="color: #993333; font-weight: bold;">GO</span><br />
<br />
<span style="color: #993333; font-weight: bold;">WITH</span> T0 <span style="color: #993333; font-weight: bold;">AS</span><br />
<span style="color: #66cc66;">&#40;</span><br />
<span style="color: #993333; font-weight: bold;">SELECT</span> DAT_DATE<span style="color: #66cc66;">,</span> <span style="color: #993333; font-weight: bold;">ROW_NUMBER</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">OVER</span><span style="color: #66cc66;">&#40;</span>PARTITION <span style="color: #993333; font-weight: bold;">BY</span> DAT_AN<span style="color: #66cc66;">,</span> DAT_MOIS <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> DAT_JOUR <span style="color: #993333; font-weight: bold;">DESC</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">-</span> <span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">AS</span> NB_JOUR_FIN_MOIS<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; T_DAT<br />
<span style="color: #66cc66;">&#41;</span><br />
<span style="color: #993333; font-weight: bold;">UPDATE</span> T<br />
<span style="color: #993333; font-weight: bold;">SET</span> &nbsp; &nbsp;DAT_NB_JOUR_FIN_MOIS <span style="color: #66cc66;">=</span> NB_JOUR_FIN_MOIS<br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; T_DAT <span style="color: #993333; font-weight: bold;">AS</span> T<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> T0 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">ON</span> T<span style="color: #66cc66;">.</span>DAT_DATE <span style="color: #66cc66;">=</span> T0<span style="color: #66cc66;">.</span>DAT_DATE;<br />
<span style="color: #993333; font-weight: bold;">GO</span><br />
<br />
<span style="color: #993333; font-weight: bold;">UPDATE</span> T<br />
<span style="color: #993333; font-weight: bold;">SET</span> &nbsp; &nbsp;DAT_JOUR_FIN_MOIS <span style="color: #66cc66;">=</span> T2<span style="color: #66cc66;">.</span>DAT_JOUR <br />
<span style="color: #993333; font-weight: bold;">FROM</span> &nbsp; T_DAT <span style="color: #993333; font-weight: bold;">AS</span> T<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> T_DAT <span style="color: #993333; font-weight: bold;">AS</span> T2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">ON</span> T<span style="color: #66cc66;">.</span>DAT_AN <span style="color: #66cc66;">=</span> T2<span style="color: #66cc66;">.</span>DAT_AN<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">AND</span> &nbsp;T<span style="color: #66cc66;">.</span>DAT_MOIS <span style="color: #66cc66;">=</span> T2<span style="color: #66cc66;">.</span>DAT_MOIS<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333; font-weight: bold;">AND</span> T2<span style="color: #66cc66;">.</span>DAT_NB_JOUR_FIN_MOIS <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">0</span><br />
<span style="color: #993333; font-weight: bold;">GO</span></div></div>
<p>Nous avons ensuite créé la fonction de calcul :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CREATE FUNCTION F_MOIS30 (@D1 DATE, @D2 DATE)<br />
RETURNS INT<br />
AS<br />
BEGIN<br />
&nbsp; &nbsp;DECLARE @AN INT, @MOIS INT, @JFM INT<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;SELECT @AN = DAT_AN, @MOIS = DAT_MOIS, @JFM = DAT_NB_JOUR_FIN_MOIS<br />
&nbsp; &nbsp;FROM &nbsp; T_DAT <br />
&nbsp; &nbsp;WHERE DAT_DATE = @D1;<br />
<br />
&nbsp; &nbsp;SELECT @AN = DAT_AN - @AN, @MOIS = DAT_MOIS - @MOIS, @JFM = @JFM + DAT_JOUR<br />
&nbsp; &nbsp;FROM &nbsp; T_DAT <br />
&nbsp; &nbsp;WHERE DAT_DATE = @D2;<br />
<br />
&nbsp; &nbsp;RETURN (@AN * 12 + @MOIS - 1) * 30 + @JFM<br />
END;<br />
GO</div></div>
<p>Il ne restait plus qu&#039;à la tester :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">SELECT dbo.F_MOIS30('2014-03-20', '2015-02-01')</div></div>
<p>Ce qui donne 312 résultat escompté !</p>
<p>CQFD</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES<br />
Expert &nbsp;S.G.B.D &nbsp;relationnelles &nbsp; et &nbsp; langage &nbsp;S.Q.L<br />
Moste &nbsp;Valuable &nbsp;Professionnal &nbsp;Microsoft &nbsp;SQL Server<br />
Société SQLspot &nbsp;: &nbsp;modélisation, conseil, formation,<br />
optimisation, &nbsp;audit, &nbsp;tuning, &nbsp;administration &nbsp;SGBDR<br />
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.</div></div>
<p>L&rsquo;entreprise <a href="http://www.sqlspot.com">SQL Spot</a><br />
<strong>Le site web sur le </strong><a href="http://sqlpro.developpez.com/">SQL et les SGBDR</a></p>
<p><img src="http://blog.developpez.com/media/Microsoft_MVP_logo_vertical Brouard 400.jpg" width="400" height="135" alt="MVP Microsoft SQL
Server" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
