<?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>SQL - Etienne ZINZINDOHOUE</title>
	<atom:link href="https://blog.developpez.com/zinzineti/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/zinzineti</link>
	<description>Bases de données</description>
	<lastBuildDate>Thu, 09 Aug 2012 13:57:35 +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>SQL Three-Valued Logic (3VL)</title>
		<link>https://blog.developpez.com/zinzineti/p11209/sgbd/sql_three_valued_logic_3vl</link>
		<comments>https://blog.developpez.com/zinzineti/p11209/sgbd/sql_three_valued_logic_3vl#comments</comments>
		<pubDate>Wed, 08 Aug 2012 21:52:40 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SGBD]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Soit les tables T1 et T2 suivantes : create table T1 (col1 int) create table T2 (col2 int) insert into T1 select 1 union select 2 union select 3 union select null insert into T2 select 4 union select 2 union select 5 union select null Pourquoi la requête SELECT * FROM T1 WHERE col1 NOT IN (SELECT col2 FROM T2) ne renvoie aucune valeur alors que SELECT * FROM T1 WHERE col1 IN (SELECT [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Soit les tables T1 et T2 suivantes :</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 table T1 (col1 int) <br />
create table T2 (col2 int) <br />
insert into T1 select 1 union select 2 union select 3 union select null <br />
insert into T2 select 4 union select 2 union select 5 union select null</div></div>
<p>Pourquoi la requête <code class="codecolorer text default"><span class="text">SELECT * FROM T1 WHERE col1 NOT IN (SELECT col2 FROM T2)</span></code> ne renvoie aucune valeur alors que<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM T1 WHERE col1 IN (SELECT col2 FROM T2)</span></code> renvoie la valeur 2 ? <span id="more-121"></span><br />
Rappelons qu&rsquo;une colonne affiche NULL lorsqu&rsquo;elle ne contient pas de valeur. En SQL une opération de comparaison peut être avoir l&rsquo;une des trois valeurs logiques suivantes : TRUE (vrai) ou FALSE (faux) ou UNKNOWN (inconnu). C&rsquo;est ce qu&rsquo;on a appelle &laquo;&nbsp;Three-Valued Logic&nbsp;&raquo; (3VL). Signalons qu&rsquo;en mathématiques, l&rsquo;algèbre de Boole est 2VL et ne connait donc que deux valeurs (VRAI ou FAUX). En SQL la valeur logique UNKNOWN est due à la présence de NULL dans une opération de comparaison.<br />
Exemple :</p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">p</font></font><font size="2"><font size="2"> </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">         </font></font><span style="color: #ffa500"><font size="2"><font size="2">condition </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">                 &eacute;tat logique</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">2</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">            </font></font><span style="color: #ffa500"><font size="2"><font size="2">p IS NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">               FALSE</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">2 </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">          </font></font><span style="color: #ffa500"><font size="2"><font size="2"> p IS NOT NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">       TRUE</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">      </font></font><span style="color: #ffa500"><font size="2"><font size="2">p IS NULL </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">             TRUE</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">NULL </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">    </font></font><span style="color: #ffa500"><font size="2"><font size="2"> p IS NOT NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">       FALSE</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">2 </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">           </font></font><span style="color: #ffa500"><font size="2"><font size="2"> p = NULL </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">             UNKNOWN</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">2 </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">           </font></font><span style="color: #ffa500"><font size="2"><font size="2"> p <> NULL </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">           UNKNOWN</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">      </font></font><span style="color: #ffa500"><font size="2"><font size="2">p = NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">              UNKNOWN (pour SQL standard)</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">NULL </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">     </font></font><span style="color: #ffa500"><font size="2"><font size="2">p <> NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">           UNKNOWN</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">      </font></font><span style="color: #ffa500"><font size="2"><font size="2"> p = 2</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">                  UNKNOWN</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><span style="color: #000080"><font size="2"><font size="2">NULL</font></font></span><font color="#008000" size="2"><font color="#008000" size="2">       </font></font><span style="color: #ffa500"><font size="2"><font size="2">p <> 2 </font></font></span><font color="#008000" size="2"><font color="#008000" size="2">               UNKNOWN</font></font></span></p>
<p>
	<span style="font-family: arial, helvetica, sans-serif"><font color="#008000" size="2"><font color="#008000" size="2">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</font></font></span></p>
<p>avec le tableau ci-dessus on peut constater que si l&rsquo;un des opérandes est NULL alors l&rsquo;opération de comparaison prend la valeur logique UNKNOWN. Pour déterminer si une expression est NULL (ou pas) il faut utiliser IS NULL (ou IS NOT NULL)</p>
<p>=> <strong>Algèbre Three-Valued Logic (3VL) et les opérateurs NOT, AND et OR</strong><br />
&#8211;> avec l&rsquo;<strong>opérateur NOT</strong><br />
NOT TRUE = FALSE<br />
NOT FALSE = TRUE<br />
NOT UNKNOWN = UNKNOWN</p>
<p>&#8211;> avec l&rsquo;<strong>opérateur AND</strong><br />
TRUE AND TRUE = TRUE<br />
TRUE AND FALSE = FALSE<br />
TRUE AND UNKNOWN = UNKNOWN</p>
<p>FALSE AND TRUE = FALSE<br />
FALSE AND FALSE = FALSE<br />
FALSE AND UNKNOWN = FALSE</p>
<p>UNKNOWN AND TRUE = UNKNOWN<br />
UNKNOWN AND FALSE = FALSE<br />
UNKNOWN AND UNKNOWN = UNKNOWN</p>
<p>&#8211;> avec l&rsquo;<strong>opérateur OR</strong><br />
TRUE OR TRUE = TRUE<br />
TRUE OR FALSE = TRUE<br />
TRUE OR UNKNOWN = TRUE</p>
<p>FALSE OR TRUE = TRUE<br />
FALSE OR FALSE = FALSE<br />
FALSE OR UNKNOWN = UNKNOWN</p>
<p>UNKNOWN OR TRUE = TRUE<br />
UNKNOWN OR FALSE = UNKNOWN<br />
UNKNOWN OR UNKNOWN = UNKNOWN</p>
<p>=> <strong>UNKNOWN avec les clauses WHERE et CHECK</strong><br />
Dans une clause WHERE une expression évaluée comme UNKNOWN se comporte comme FALSE et dans ce cas aucune ligne n&rsquo;est renvoyée.<br />
Exemple :<br />
<code class="codecolorer text default"><span class="text">select * from T1 where col1 not in (select col2 from T2)</span></code><br />
Par contre dans une clause CHECK une expression évaluée comme UNKNOWN se comporte comme TRUE et l&rsquo;expression est considérée comme valide<br />
Exemple</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 table T2 (col2 int , CONSTRAINT CHK CHECK (col2 &lt; 10)) <br />
insert into T2 select 4 union select 2 union select null</div></div>
<p>&#8212; insertion réalisée</p>
<p>=> <strong>opération arithmétique avec NULL renvoie NULL</strong> et peut donc provoquer un état logique UNKNOWN lors d&rsquo;une comparaison</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 3 + null &nbsp; <br />
SELECT 3 - null <br />
SELECT 3 * null <br />
SELECT 3 /null</div></div>
<p>=> <strong>La plupart des fonctions d&rsquo;agregation ignorent NULL</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">select AVG(col2) from T2 &nbsp;-- donne (4+2)/2 = 3 &nbsp;ici null est ignoré <br />
select COUNT(*) from T2 &nbsp;-- donne 4 : ici null n'est pas ignoré <br />
select COUNT(col2) from T2 -- donne 3 : ici null est ignoré</div></div>
<p>=> Les opérateurs ensemblistes <strong>UNION,INTERSECT,EXCEPT n&rsquo;ignorent pas NULL</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">select * from T1 &nbsp;UNION &nbsp;select * from T2 <br />
select * from T1 &nbsp;EXCEPT &nbsp;select * from T2 <br />
select * from T1 &nbsp;INTERSECT &nbsp;select * from T2</div></div>
<p>=> <strong>CASE expression </strong>: attention lorsque la clause ELSE n&rsquo;est pas explicite ELSE NULL est rajouté !<br />
Exemple</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 case col1 &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; when 1 then 1 <br />
&nbsp; &nbsp; &nbsp; &nbsp; when 2 then 2 <br />
&nbsp; &nbsp; &nbsp; &nbsp; when 3 then 3 <br />
&nbsp; &nbsp; &nbsp; &nbsp; END <br />
FROM T1</div></div>
<p>Les fonctions CASE, COALESCE, &#8230; permettent de traiter les NULLs afin d&rsquo;obtenir les résultats escomptés. </p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>IPv4 : Stockage et Manipulations</title>
		<link>https://blog.developpez.com/zinzineti/p11081/sql-server-2008/ipv4_stockage_et_manipulations</link>
		<comments>https://blog.developpez.com/zinzineti/p11081/sql-server-2008/ipv4_stockage_et_manipulations#comments</comments>
		<pubDate>Fri, 08 Jun 2012 17:26:29 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La norme SQL n&#8217;a rien proposé jusqu&#8217;à ce jour pour stocker les types de données network (IPv4, IPv6, masque de sous-réseau,&#8230;) . Les &#171;&#160;grands&#160;&#187; éditeurs de SGBD ne disposent pas encore de types de données capable de stocker et de manipuler aisément les données de types IP par exemple. Dans ce domaine PostGreSQL est largement en avance. Pour illustrer mes propos prenons un exemple simple : Imaginer une application web qui stocke l&#8217;adresse IP des [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La norme SQL n&rsquo;a rien proposé jusqu&rsquo;à ce jour pour stocker les types de données network (IPv4, IPv6, masque de sous-réseau,&#8230;) . Les &laquo;&nbsp;grands&nbsp;&raquo; éditeurs de SGBD ne disposent pas encore de types de données capable de stocker et de manipuler aisément les données de types IP par exemple. Dans ce domaine PostGreSQL est largement en avance. Pour illustrer mes propos prenons un exemple simple :<br />
Imaginer une application web qui stocke l&rsquo;adresse IP des ordinateurs des utilisateurs dans une table nommée &laquo;&nbsp;TableDesIPs&nbsp;&raquo;  pour faciliter un certain nombre d&rsquo;opérations : identification, redirection, restriction, filtrage, &#8230; SQL Server et ORACLE sont aujourd&rsquo;hui incapables de donner une réponse favorable à la requête suivante : <strong><code class="codecolorer text default"><span class="text">SELECT IP_VISITEUR FROM TableDesIPs WHERE IP_VISITEUR &gt; IP_MIN AND IP_VISITEUR &lt; IP_ADR_MAX</span></code></strong><br />
C&rsquo;est à dire lister les adresses IP membre d&rsquo;une plage d&rsquo;adresse IP. La borne inférieure de la plage est IP_MIN et la borne supérieure IP_MAX.<br />
Par contre PostGreSQL se démarque en implémentant les types de données : <strong>CIDR</strong> et <strong>INET</strong> qui permettent de stocker et de manipuler aisément les données de type IP. Voyons quelques rustines pour stocker des données IPv4 et MAC-48 sous SQL Server <span id="more-105"></span><br />
Quelques rustines pour stocker des données IPv4 sous SQL Server<br />
=> <strong>Stocker IPv4 sous SQL Server</strong></p>
<p><strong>&#8211;> Création de la fonction de validation d&rsquo;IPv4</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">CREATE FUNCTION [dbo].[IsIPv4](@IsIPv4 CHAR(19)) <br />
RETURNS SMALLINT <br />
AS <br />
BEGIN <br />
DECLARE @IsOK SMALLINT; <br />
-- Vérifier si on que des nombres en dehors des points <br />
IF (ISNUMERIC(REPLACE(@IsIPv4,'.',''))=1 <br />
-- Vérifier s'il y a 3 points dans la chaine &nbsp; &nbsp;<br />
&nbsp; &nbsp; AND LEN(@IsIPv4) - LEN(REPLACE(@IsIPv4,'.','')) = 3 <br />
-- Vérifier que les nombres de bits pour l'IPV4 est compris entre 0 et 255 &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; AND 0 &lt;= CAST(PARSENAME(@IsIPv4,1) as SMALLINT) AND CAST(PARSENAME(@IsIPv4,1) as SMALLINT) &lt;= 255 <br />
&nbsp; &nbsp; AND 0 &lt;= CAST(PARSENAME(@IsIPv4,2) as SMALLINT) AND CAST(PARSENAME(@IsIPv4,2) as SMALLINT) &lt;= 255 <br />
&nbsp; &nbsp; AND 0 &lt;= CAST(PARSENAME(@IsIPv4,3) as SMALLINT) AND CAST(PARSENAME(@IsIPv4,3) as SMALLINT) &lt;= 255 <br />
&nbsp; &nbsp; AND 0 &lt;= CAST(PARSENAME(@IsIPv4,4) as SMALLINT) AND CAST(PARSENAME(@IsIPv4,4) as SMALLINT) &lt;= 255 <br />
&nbsp; &nbsp; ) <br />
SELECT @IsOK = 1 &nbsp;<br />
ELSE <br />
SET @IsOK = 0 <br />
RETURN @IsOK &nbsp;<br />
END</div></div>
<p><strong>&#8211;> Test de Stockage d&rsquo;IP</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">CREATE TABLE TableIPv4 (ID INT IDENTITY, IPv4 CHAR(19) CHECK (dbo.IsIPv4 (IPv4)=1)) <br />
INSERT TableIPv4 VALUES('10.276.33.25')</div></div>
<blockquote><p>Msg 547, Level 16, State 0, Line 1<br />
The INSERT statement conflicted with the CHECK constraint &laquo;&nbsp;CK__TableIPv4__IPv4__090A5324&Prime;. The conflict occurred in database &laquo;&nbsp;AdventureWorks&nbsp;&raquo;, table &laquo;&nbsp;dbo.TableIPv4&Prime;, column &lsquo;IPv4&prime;.<br />
The statement has been terminated.</p></blockquote>
<p><code class="codecolorer text default"><span class="text">INSERT TableIPv4 VALUES('10.226.33.25')</span></code></p>
<blockquote><p>
(1 row(s) affected)
</p></blockquote>
<p>Comment stocker des adresses mac sous SQL Server ?<br />
Rappelons que l&rsquo;adresse MAC-48 est constituée de 48 bits (6 octets) se représente sous la forme hexadécimale avec les octets séparés par deux point (:) ou par un tiret (-)<br />
Exemples :<br />
&#8212;&#8212;&#8211;<br />
08-00-2B-01-02-03<br />
08:00:2B:01:02:03 </p>
<p>=> <strong>Stocker ADRESSE MAC sous SQL Server </strong></p>
<p><strong>&#8211;> Création de la fonction de validation MAC-48</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">CREATE &nbsp;FUNCTION [dbo].[IsMacAddress48](@MacAddress CHAR(17)) <br />
RETURNS SMALLINT <br />
AS <br />
BEGIN <br />
DECLARE @IsOK SMALLINT; <br />
-- Vérifier si on que des nombres en dehors des points <br />
IF (LEN(REPLACE(REPLACE(@MacAddress,'-',''),':',''))= 12 <br />
-- Vérifier s'il y a 3 points dans la chaine &nbsp; &nbsp;<br />
&nbsp; &nbsp; AND (@MacAddress LIKE '[0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F]' <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OR @MacAddress LIKE '[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]' <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;) &nbsp;<br />
&nbsp; &nbsp; ) <br />
SELECT @IsOK = 1 &nbsp;<br />
ELSE <br />
SET @IsOK = 0 <br />
RETURN @IsOK &nbsp;<br />
END</div></div>
<p><strong>&#8211;> Test de Stockage de MAC-48</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">CREATE TABLE TableMacAddress48 (ID INT IDENTITY, MacAddress48 CHAR(17) CHECK (dbo.IsMacAddress48(MacAddress48)=1)) <br />
INSERT TableMacAddress48 VALUES('08-00-2G-01-02-03')</div></div>
<blockquote><p>
Msg 547, Level 16, State 0, Line 1<br />
The INSERT statement conflicted with the CHECK constraint &laquo;&nbsp;CK__TableMacA__MacAd__0CDAE408&Prime;. The conflict occurred in database &laquo;&nbsp;AdventureWorks&nbsp;&raquo;, table &laquo;&nbsp;dbo.TableMacAddress48&Prime;, column &lsquo;MacAddress48&prime;.<br />
The statement has been terminated.
</p></blockquote>
<p>INSERT TableMacAddress48 VALUES(&rsquo;08-00-2B-01-02-03&prime;)</p>
<blockquote><p>
(1 row(s) affected)
</p></blockquote>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
&#8212; Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Transactions implicite, explicite et autocommit</title>
		<link>https://blog.developpez.com/zinzineti/p11007/sql-server-2008/transactions_implicite_explicite_et_auto</link>
		<comments>https://blog.developpez.com/zinzineti/p11007/sql-server-2008/transactions_implicite_explicite_et_auto#comments</comments>
		<pubDate>Tue, 01 May 2012 00:24:07 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Petite discussion sur les transactions implicite, explicite et auto-commit d&#8217;une part et variation de la variable @@TRANCOUNT en fonction de l&#8217;option SET IMPLICIT_TRANSACTIONS d&#8217;autre part. Il s&#8217;agit ici des transactions SQL, des transactions au sein du SGBD SQL Server. => Transaction explicite &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- Une transaction est dite explicite lorsqu&#8217;on indique le début (BEGIN TRANSACTION) et la fin (COMMIT TRANSACTION ou ROLLBACK TRANSACTION) de la transaction Exemple &#8212;&#8212;&#8211; BEGIN TRANSACTION -- ici instruction(s) SQL create table [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Petite discussion sur les transactions implicite, explicite et auto-commit d&rsquo;une part et variation de la variable @@TRANCOUNT en fonction de l&rsquo;option SET IMPLICIT_TRANSACTIONS d&rsquo;autre part. Il s&rsquo;agit ici des transactions SQL, des transactions au sein du SGBD SQL Server.<br />
<span id="more-104"></span><br />
=> <strong>Transaction  explicite</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Une transaction est dite explicite lorsqu&rsquo;on indique le début (BEGIN TRANSACTION) et la fin (COMMIT TRANSACTION ou ROLLBACK TRANSACTION) de la transaction</p>
<p>Exemple<br />
&#8212;&#8212;&#8211;</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">BEGIN TRANSACTION <br />
-- ici instruction(s) SQL <br />
create table t (col char(1)) <br />
insert into t values ('1') <br />
COMMIT TRANSACTION</div></div>
<p>=> <strong>Transaction implicite</strong><br />
Une transaction est dite implicite lorsqu&rsquo;il n&rsquo;y a pas de BEGIN TRANSACTION pour indiquer le début de la transaction. Cette dernière est automatiquement démarrée par l&rsquo;une des commandes :<br />
<code class="codecolorer text default"><span class="text">ALTER TABLE, CREATE, DELETE, DROP, FETCH, GRANT, INSERT, OPEN, REVOKE, SELECT, TRUNCATE TABLE, UPDATE</span></code> <strong>mais il est indispensable de valider la transaction implicite par COMMIT TRANSACTION ou de l&rsquo;annuler avec ROLLBACK TRANSACTION</strong>.<br />
Pour activer ce mode de fonctionnement sous SQL Server, il suffit d&rsquo;exécuter la commande :<br />
<strong>SET IMPLICIT_TRANSACTIONS ON</strong></p>
<p>Exemple<br />
&#8212;&#8212;&#8211;</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">SET IMPLICIT_TRANSACTIONS ON <br />
-- ici instruction(s) SQL <br />
create table t (col char(1)) <br />
insert into t values ('1') <br />
COMMIT TRANSACTION</div></div>
<p>=> <strong>Autocommit</strong><br />
Si en l&rsquo;abscence des verbes <strong>BEGIN TRANSACTION</strong>, <strong>COMMIT TRANSACTION</strong> ou <strong>ROLLBACK TRANSACTION</strong> chaque instruction SQL est considérée comme une transaction alors on dit qu&rsquo;on est en mode autocommit. Dans ce cas chaque instruction SQL est automatiquement validée (s&rsquo;il n&rsquo;y a pas d&rsquo;erreur) ou annuler (s&rsquo;il y a erreur). C&rsquo;est le mode de fonctionnement par défaut sous SQL Server. Pour activer ce mode de fonctionnement sous SQL Server, il suffit d&rsquo;exécuter la commande :<br />
<strong>SET IMPLICIT_TRANSACTIONS OFF</strong></p>
<p>Exemple<br />
&#8212;&#8212;&#8211;</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">SET IMPLICIT_TRANSACTIONS OFF <br />
create table t (col char(1)) <br />
insert into t values ('1') <br />
insert into t values ('12') -- échec lors de l'insertion de cette ligne <br />
select * from t &nbsp;-- on a une ligne dans la table</div></div>
<p>=> <strong>@@TRANCOUNT en fonction de l&rsquo;option IMPLICIT_TRANSACTIONS</strong><br />
<strong>&#8211;>1# @@TRANCOUNT et SET IMPLICIT_TRANSACTIONS OFF</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">SET IMPLICIT_TRANSACTIONS OFF <br />
print '@@TRANCOUNT avant begin : ' + cast (@@TRANCOUNT as char(1)) <br />
BEGIN TRANSACTION <br />
print '@@TRANCOUNT après begin : ' + cast (@@TRANCOUNT as char(1)) <br />
create table t (col char(1)) <br />
print '@@TRANCOUNT après create : ' + cast (@@TRANCOUNT as char(1)) <br />
insert into t values ('1') <br />
print '@@TRANCOUNT après insert : ' + cast (@@TRANCOUNT as char(1)) <br />
COMMIT TRANSACTION <br />
print '@@TRANCOUNT après commit : ' + cast (@@TRANCOUNT as char(1))</div></div>
<blockquote><p>Résultat<br />
&#8212;&#8212;&#8212;<br />
@@TRANCOUNT avant begin : 0<br />
@@TRANCOUNT après begin : 1<br />
@@TRANCOUNT après create : 1<br />
(1 row(s) affected)<br />
@@TRANCOUNT après insert : 1<br />
@@TRANCOUNT après commit : 0</p></blockquote>
<p><strong>&#8211;>2#@@TRANCOUNT et IMPLICIT_TRANSACTIONS ON avec BEGIN TRANSACTION </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">SET IMPLICIT_TRANSACTIONS ON <br />
print '@@TRANCOUNT avant begin : ' + cast (@@TRANCOUNT as char(1)) <br />
BEGIN TRANSACTION <br />
print '@@TRANCOUNT après begin : ' + cast (@@TRANCOUNT as char(1)) <br />
create table t (col char(1)) <br />
print '@@TRANCOUNT après create : ' + cast (@@TRANCOUNT as char(1)) <br />
insert into t values ('1') <br />
print '@@TRANCOUNT après insert : ' + cast (@@TRANCOUNT as char(1)) <br />
COMMIT TRANSACTION <br />
print '@@TRANCOUNT après commit : ' + cast (@@TRANCOUNT as char(1))</div></div>
<blockquote><p>Résultat<br />
&#8212;&#8212;&#8212;<br />
@@TRANCOUNT avant begin : 0<br />
@@TRANCOUNT après begin : 2<br />
@@TRANCOUNT après create : 2<br />
(1 row(s) affected)<br />
@@TRANCOUNT après insert : 2<br />
@@TRANCOUNT après commit : 1
</p></blockquote>
<p><strong>&#8211;>3#@@TRANCOUNT et IMPLICIT_TRANSACTIONS ON sans BEGIN TRANSACTION</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">SET IMPLICIT_TRANSACTIONS ON <br />
print '@@TRANCOUNT après set implicit on &nbsp;: ' + cast (@@TRANCOUNT as char(1)) <br />
create table t (col char(1)) <br />
print '@@TRANCOUNT après create : ' + cast (@@TRANCOUNT as char(1)) <br />
insert into t values ('1') <br />
print '@@TRANCOUNT après insert : ' + cast (@@TRANCOUNT as char(1)) <br />
COMMIT TRANSACTION <br />
print '@@TRANCOUNT après commit : ' + cast (@@TRANCOUNT as char(1))</div></div>
<blockquote><p>Résultat<br />
&#8212;&#8212;&#8212;<br />
@@TRANCOUNT après set implicit on  : 1<br />
@@TRANCOUNT après create : 1<br />
(1 row(s) affected)<br />
@@TRANCOUNT après insert : 1<br />
@@TRANCOUNT après commit : 0
</p></blockquote>
<p>Bonne fête du travail <img src="https://blog.developpez.com/zinzineti/wp-includes/images/smilies/icon_smile.gif" alt=":-)" class="wp-smiley" /> </p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>blocage &#8211; interblocage : lock &#8211; deadlock</title>
		<link>https://blog.developpez.com/zinzineti/p10978/sql-server-2008/blocage_interblocage_lock_deadlock</link>
		<comments>https://blog.developpez.com/zinzineti/p10978/sql-server-2008/blocage_interblocage_lock_deadlock#comments</comments>
		<pubDate>Mon, 23 Apr 2012 18:47:33 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Lorsque deux processus (instructions sql) tentent simultanément de modifier (INSERT,UPDATE,DELETE) les mêmes données, le SGBD empêche les traitements simultanés de ces processus afin de protéger les données et l&#8217;intégrité de la base. SQL Server crée un verrou pour chaque processus et les gère selon un agorithme FIFO (First In First Out). Dans ce cas SQL Server impose un traitement en série dans instructions, ce qui entraine donc des temps d&#8217;attente, donc des blocages. Mais lorsque [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Lorsque deux processus (instructions sql) tentent simultanément de modifier (INSERT,UPDATE,DELETE) les mêmes données, le SGBD empêche les traitements simultanés de ces processus afin de protéger les données et l&rsquo;intégrité de la base. SQL Server crée un verrou pour chaque processus et les gère selon un agorithme FIFO (First In First Out). Dans ce cas SQL Server impose un traitement en série dans instructions, ce qui entraine donc des temps d&rsquo;attente, donc des blocages. Mais lorsque ce blocage dure longtemps, les applications qui pointent vers la base de données deviennent inutilisables et les utilisateurs ne sont pas contents &#8230;<br />
Dans ce billet, nous mettre en évidence quelques situations provoquant des blocages, des interblocages et des pistes pour anticiper/gérer aux mieux ces situations. <span id="more-103"></span></p>
<p>Dans les exemples qui vont suivre nous allons utiliser deux sessions via SQL Server Management Studio (ssms)<br />
Pour passer d&rsquo;une session à une autre j&rsquo;ai préféré la présentation ci-dessous pour plus de confort visuel.<br />
Une fois les deux fenêtre ouvertes, clique droit sur l&rsquo;onglet</p>
<p><img src="http://zinzineti.ftp-developpez.com/images/session1.jpg" alt="visu1" title="visu1" /></p>
<p>Choisir l&rsquo;affichage verticale des sessions</p>
<p><img src="http://zinzineti.ftp-developpez.com/images/session2.jpg" alt="visu1" title="visu1" /></p>
<p>=> <strong>Mise en évidence d&rsquo;un blocage </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">-- Création de la table &nbsp;<br />
IF OBJECT_ID('T') IS NOT NULL DROP TABLE T &nbsp;<br />
CREATE TABLE T (id INT,col CHAR(1)) &nbsp;<br />
-- insertion des données dans la table &nbsp;<br />
INSERT INTO T (id,col) VALUES (1,'a') &nbsp;<br />
INSERT INTO T (id,col) VALUES (2,'b')</div></div>
<p>Supposons que deux utilisateurs veulent exécuter presque au même moment, la même transaction. </p>
<p>&#8211;> <strong>Session 1</strong> (utilisateur 1)  : démarrer la transaction suivante<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">BEGIN TRAN &nbsp;<br />
UPDATE T &nbsp;<br />
SET col = 'c' <br />
WHERE id = 1 <br />
/* <br />
Résultat : UPDATE effectué dans la session 1 <br />
*/</div></div>
<p>&#8211;> <strong>Session 2</strong> (utilisateur 2)  : démarrer la transaction suivante<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">BEGIN TRAN &nbsp;<br />
UPDATE T <br />
SET col = 'd' <br />
WHERE id = 1 <br />
/* <br />
Résultat : UPDATE mis en attente dans la session 2, le processus est bloqué ! <br />
*/</div></div>
<p><strong>&#8211;> Comment identifier les processus bloqués sur une instance ?</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">SELECT session_id,start_time,wait_time,status,wait_type,command,blocking_session_id,transaction_id &nbsp; <br />
FROM sys.dm_exec_requests &nbsp;<br />
WHERE blocking_session_id &lt;&gt; 0 <br />
&nbsp;<br />
SELECT spid,open_tran,blocked &nbsp;<br />
FROM sys.sysprocesses WHERE blocked &lt;&gt; 0</div></div>
<p>L&rsquo;ID des sessions (session_id ou spid) responsables du blocage sont donc identifiés .</p>
<p><strong>&#8211;> Comment mettre fin à ce blocage ?</strong></p>
<p>Il suffit de tuer le processus responsable du blocage à l&rsquo;aide la commande suivante :</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">KILL &lt;spid&gt; <br />
Exemple <br />
-------- <br />
KILL 54</div></div>
<p>Cette commande annule toutes les transactions liées à ce processus. Cette opération est tracé dans les fichiers de<br />
d&rsquo;erreurs SQL Server (ERRLOG) et Event Viewver Application (\WINDOWS\system32\config\AppEvent.Evt)</p>
<p>=> <strong>Interblocage des transactions SQL  : deadlock &#8211; verrou mortel</strong><br />
Le phénomène d&rsquo;interblocage (deadlock) se présente lorsque plusieurs processus (transactions sql) se bloquent de façon à ce qu&rsquo;aucun de ces processus ne peut se débloquer quelque soit la durée d&rsquo;attente.<br />
Ceci apparaît lors de la modification des données(INSERT, UPDATE, DELETE). Dans ce cas le gestionnaire de verrou SQL Server détecte qu&rsquo;il y a un deadlock et va donc tuer un des processus, annuler la totalité des<br />
transactions sql du processus liquidé et renvoyé le code d&rsquo;erreur 1205 à la session concernée.<br />
Sur quels critères SQL Server choisit la processus à tuer ? Pour deux transactions ayant la même priorité, les règles de sélection du processus à liquider ne sont pas clairement détaillées par Microsoft .<br />
Rappelons que l&rsquo;option SET DEADLOCK_PRIORITY { LOW | NORMAL | HIGH } permet de spécifier la priorité d&rsquo;une transaction en cas de deadlock.</p>
<p>Ouvrons une petite parenthèse : Sous ORACLE le code d&rsquo;erreur des deadlocks est ORA-00060 (détection d&rsquo;interblocage pendant l&rsquo;attente d&rsquo;une ressource) et fermons cette parenthèse</p>
<p><strong>&#8211;> Mise en évidence du phénonème de verrou mortel (deadlock)</strong><br />
<strong>&#8211; # Cas une table : objet non distinct</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">-- Création de la table <br />
IF OBJECT_ID('T') IS NOT NULL DROP TABLE T <br />
CREATE TABLE T (id INT,col CHAR(1)) &nbsp;<br />
-- insertion des données dans la table &nbsp;<br />
INSERT INTO T (id,col) VALUES (1,'a') &nbsp;<br />
INSERT INTO T (id,col) VALUES (2,'b')</div></div>
<p>Dans la <strong>session 1</strong>, démarrer la transaction suivante :</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">BEGIN TRAN &nbsp;<br />
UPDATE T <br />
SET col = 'c' <br />
WHERE id = 2</div></div>
<p>/*<br />
Résultat : UPDATE effectué dans la session 1<br />
*/</p>
<p>&#8212; Dans la <strong>session 2</strong>, démarrer la transaction suivante  :</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">BEGIN TRAN &nbsp;<br />
UPDATE T <br />
SET col = 'e' <br />
WHERE id = 1</div></div>
<p>/*<br />
Résultat : UPDATE en attente dans la session 2<br />
*/</p>
<p>&#8212; Dans la <strong>session 1</strong>, exécuter la requête suivante :</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">UPDATE T <br />
SET col = 'f' <br />
WHERE id = 2</div></div>
<p>/*<br />
Résultat : un message d&rsquo;erreur apparaît dans la session 1.<br />
Msg 1205, Level 13, State 45, Line 1<br />
Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.</p>
<p>dans la session 2, la mis à jour est réalisée</p>
<p>&#8212; Vérification de la modification dans la session 2<br />
<code class="codecolorer text default"><span class="text">select * from T where id = 1</span></code></p>
<p>id	col<br />
&#8212;&#8212;-<br />
1	e</p>
<p>*/</p>
<p><strong>Comment résoudre ce problème dans ce cas  ?</strong></p>
<p>Pour contouner ce deadlock, il suffit de créer sur cette table un index du genre :<br />
<code class="codecolorer text default"><span class="text">CREATE INDEX IX ON T (id) INCLUDE (col)</span></code><br />
Et le tour est joué !</p>
<p><strong>&#8211; # Cas de deux tables distinctes : objets distincts </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">-- Création des deux tables <br />
IF OBJECT_ID('T1') IS NOT NULL DROP TABLE T1 &nbsp;<br />
IF OBJECT_ID('T2') IS NOT NULL DROP TABLE T2 &nbsp;<br />
CREATE TABLE T1 (id1 INT,col1 CHAR(1)) &nbsp;<br />
CREATE TABLE T2 (id2 INT,col2 CHAR(1)) &nbsp;<br />
-- insertion des données dans la table &nbsp;<br />
INSERT INTO T1 (id1,col1) VALUES (1,'a') &nbsp;<br />
INSERT INTO T2 (id2,col2) VALUES (2,'b')</div></div>
<p>Dans la <strong>session 1</strong>, démarrer la transaction suivante :</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">BEGIN TRAN &nbsp;<br />
UPDATE T1 <br />
SET col1 = 'c' <br />
WHERE id1 = 1</div></div>
<p>/*<br />
Résultat : UPDATE effectué dans la session 1<br />
*/</p>
<p>Dans la <strong>session 2</strong>, démarrer la transaction suivante  :</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">BEGIN TRAN &nbsp;<br />
UPDATE T2 <br />
SET col2 = 'd' <br />
WHERE id2 = 2</div></div>
<p>/*<br />
Résultat : UPDATE effectué dans la session 2<br />
*/</p>
<p>Dans la <strong>session 1</strong>, exécuter la requête suivante :</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">UPDATE T2 <br />
SET col2 = 'e' <br />
WHERE id2 = 2</div></div>
<p>/*<br />
Résultat : UPDATE en attente dans la session 2<br />
*/</p>
<p>Dans la <strong>session 2</strong>, exécuter la requête suivante :</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">UPDATE T1 <br />
SET col1 = 'f' <br />
WHERE id1 = 1</div></div>
<p>/*<br />
Résultat :<br />
Msg 1205, Level 13, State 45, Line 1<br />
Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.<br />
*/</p>
<p>Dans ce cas, la <strong>création des index sur les tables T1 et T2 ne permet pas de solutionner le problème</strong>. Une piste consiste à catcher l&rsquo;erreur 1205 (TRY/CATCH) puis tenter de rejouer la transaction. D&rsquo;autres solutions existent, mais avant de les présenter examinons d&rsquo;abord comment identifier les instructions responsables du deadlock sur une instance</p>
<p>=> <strong>Comment identifier les instructions responsable du deadlock ?</strong><br />
<strong>&#8211; # Avec XEvents</strong><br />
Sous SQL Server 2008 et + on peut utiliser XEvents pour collecter les informations relatives aux deadlocks.<br />
La requête ci-dessous renvoie un fichier XML montrant les requêtes responsables des deadlocks. On peut faire des filtres horodatages pour cibler les deadlocks ayant lieu à un moment donnée.</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">DECLARE @xml xml <br />
SELECT @xml = CAST(st.target_data as xml) <br />
FROM sys.dm_xe_session_targets st <br />
INNER JOIN sys.dm_xe_sessions s on s.address = st.event_session_address <br />
INNER JOIN sys.server_event_sessions es on s.name = es.name <br />
WHERE s.name = 'system_health' AND st.target_name = 'ring_buffer' <br />
-- and convert(varchar(8),s.create_time,112) = '20120422' -- cibler une date particulière <br />
SELECT @xml.query('/RingBufferTarget/event [@name=&quot;xml_deadlock_report&quot;]')</div></div>
<p><strong>&#8211; # Avec la trace 1222 </strong><br />
Activer Trace Flag 1222 option -1 :<br />
{1222} : pour collecter toutes les informations relatives aux deadlocks.<br />
{-1} : appliquer la collecte des traces deadlock à toutes les sessions et à tous les utilisateurs</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">DBCC TRACEON (1222, -1) <br />
&nbsp;<br />
-- voir le status des traces <br />
DBCC TRACESTATUS(1222,-1)</div></div>
<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">TraceFlag &nbsp; &nbsp;Status &nbsp; &nbsp;Global &nbsp; &nbsp; &nbsp; &nbsp;Session <br />
----------------------------------------------------- <br />
1222 &nbsp;----- &nbsp; &nbsp; &nbsp;1 &nbsp; ----- &nbsp; &nbsp; &nbsp; &nbsp; 1 &nbsp; &nbsp; ----- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0</div></div>
<p>L&rsquo;activation de la trace 1222 option -1 permet de cibler le problème et d&rsquo;identifier les instructions responsables de l&rsquo;interblocage. Voici ce qu&rsquo;on observe dans le fichier ERRORLOG après activation des traces et reproduction du premier scénario (cas d&rsquo;un même objet) deadlock </p>
<blockquote><p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
&#8212; Fichier de log emplacement : \Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\ERRORLOG<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
2012-04-22 19:43:47.15 spid56      DBCC TRACEON 1222, server process ID (SPID) 56. This is an informational message only; no user action is required.<br />
2012-04-22 19:44:11.92 spid53      Starting up database &lsquo;AdventureWorks2008R2&prime;.<br />
2012-04-22 19:44:36.56 spid19s     deadlock-list<br />
2012-04-22 19:44:36.56 spid19s      deadlock victim=processd0bc78<br />
2012-04-22 19:44:36.56 spid19s       process-list<br />
2012-04-22 19:44:36.56 spid19s        process id=processd0bc78 taskpriority=0 logused=208 waitresource=RID: 6:1:15160:0 waittime=1429 ownerId=170698 transactionname=user_transaction lasttranstarted=2012-04-19T19:44:21.183 XDES=0x4338ac08 lockMode=U schedulerid=1 kpid=5488 status=suspended spid=56 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2012-04-19T19:44:35.137 lastbatchcompleted=2012-04-19T19:44:21.190 lastattention=2012-04-19T16:41:08.620 clientapp=Microsoft SQL Server Management Studio &#8211; Query hostname=XX-XX hostpid=4064 loginname=xx isolationlevel=read committed (2) xactid=170698 currentdb=6 lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200<br />
2012-04-22 19:44:36.56 spid19s         executionStack<br />
2012-04-22 19:44:36.56 spid19s          frame procname=adhoc line=1 stmtstart=58 sqlhandle=0x020000003737ba3a21719d4dd9cf31b6b7211a6fb6e2e5d1<br />
2012-04-22 19:44:36.56 spid19s     UPDATE [T] set [col] = @1  WHERE [id]=@2<br />
2012-04-22 19:44:36.56 spid19s          frame procname=adhoc line=1 sqlhandle=0x02000000fcf4a3305a4444f97c3ec147da8f12aa2b69fcd2<br />
2012-04-22 19:44:36.56 spid19s     UPDATE T<br />
2012-04-22 19:44:36.56 spid19s     SET col = &lsquo;f&rsquo;<br />
2012-04-22 19:44:36.56 spid19s     WHERE id = 2<br />
2012-04-22 19:44:36.56 spid19s         inputbuf<br />
&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;..<br />
&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;..<br />
&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;..
</p></blockquote>
<p>Dans le fichier de trace ERRLOG on identifie clairement :<br />
* les requêtes responsables du deadlock,<br />
* les objets concernés (nom du serveur,nom de la base,nom des tables,&#8230;)<br />
<strong>&#8211; # Autres méthodes d&rsquo;identification des deadlocks</strong> :<br />
Mise en place des traces via SQL Server Profiler ou ajout de l&rsquo;option &lsquo;-T1222&prime; lors du redémarrage de l&rsquo;instance SQL SERVER</p>
<p>=> <strong>Quelques pistes pour anticiper/gérer les deadlocks</strong></p>
<p>&#8211;# Ecrire des requêtes courtes et précises sur des tables bien indexées.<br />
&#8211;# Respecter le même ordre d&rsquo;exécution des requêtes dans les transactions (voir exemple plus bas)<br />
&#8211;# Catcher (TRY/CATCH) l&rsquo;erreur 1205  puis  ré-exécuter la transaction (voir exemple plus bas)<br />
&#8211;# Utiliser si possible l&rsquo;option SET DEADLOCK_PRIORITY pour générer les priorités entre les transactions en cas de deadlock</p>
<p><strong>&#8211;> Exemples : Gestion des erreurs 1205 (TRY/CATCH)</strong></p>
<p><strong>&#8211; Exemple 1 </strong> : TRY/CATCH simple<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</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">BEGIN TRY <br />
/* Mettre ici les opérations à effectuer */ <br />
END TRY <br />
BEGIN CATCH <br />
IF ERROR_NUMBER() = 1205 RAISERROR('deadlock erreur !', 16, 1); &nbsp;<br />
ELSE RAISERROR('Pas de deadlock mais une autre erreur est survenue ! ', 16, 1); &nbsp;<br />
END CATCH;</div></div>
<p><strong>&#8211; Exemple 2</strong> : TRY/CATCH avec Re-exécution de la requête<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</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">DECLARE @RetriesCounter int; &nbsp;<br />
SET @RetriesCounter = 3; &nbsp;<br />
WHILE @RetriesCounter &gt; 0 &nbsp;<br />
BEGIN &nbsp;<br />
&nbsp; &nbsp; BEGIN TRY &nbsp;<br />
/* Mettre ici les opérations à effectuer */ &nbsp;<br />
&nbsp; &nbsp; END TRY &nbsp;<br />
&nbsp; &nbsp; BEGIN CATCH &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; IF ERROR_NUMBER() = 1205 &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; BEGIN &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SET @RetriesCounter = @RetriesCounter - 1; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IF @RetriesCounter = 0 RAISERROR('Impossible de terminer la transaction !', 16, 1); &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; END &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; ELSE &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RAISERROR('Pas de deadlock mais autre erreur ! ', 16, 1); &nbsp;<br />
&nbsp; &nbsp; END CATCH &nbsp;<br />
END;</div></div>
<p>&#8211;> <strong>Exemple : Respecter le même ordre d&rsquo;exécution des transactions</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">IF OBJECT_ID('T1') IS NOT NULL DROP TABLE T1 &nbsp;<br />
IF OBJECT_ID('T2') IS NOT NULL DROP TABLE T2 &nbsp;<br />
CREATE TABLE T1 (id1 INT,col1 CHAR(1)) &nbsp;<br />
CREATE TABLE T2 (id2 INT,col2 CHAR(1)) &nbsp;<br />
-- insertion des données dans la table &nbsp;<br />
INSERT INTO T1 (id1,col1) VALUES (1,'a') &nbsp;<br />
INSERT INTO T2 (id2,col2) VALUES (2,'b')</div></div>
<p>exécuter dans la <strong>session 1</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">BEGIN TRAN <br />
UPDATE t1 SET col1 = 'x' <br />
WAITFOR DELAY '00:00:05' <br />
UPDATE t2 SET col2 = 'y' <br />
ROLLBACK TRAN</div></div>
<p>exécuter dans la <strong>session 2</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">BEGIN TRAN <br />
UPDATE t2 SET col2 = 'y' <br />
WAITFOR DELAY '00:00:05' <br />
UPDATE t1 SET col1 = 'x' <br />
ROLLBACK TRAN</div></div>
<p>/* Résultat :<br />
(1 row(s) affected)<br />
Msg 1205, Level 13, State 45, Line 6<br />
Transaction (Process ID 55) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.<br />
*/</p>
<p>&#8211;> <strong>Solution : Exécution des requêtes dans le même ordre</strong></p>
<p>exécuter dans la <strong>session 1</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">BEGIN TRAN <br />
UPDATE t1 SET col1 = 'x' <br />
WAITFOR DELAY '00:00:05' <br />
UPDATE t2 SET col2 = 'y' <br />
ROLLBACK TRAN</div></div>
<p>exécuter dans la <strong>session 2</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">BEGIN TRAN <br />
UPDATE t1 SET col1 = 'x' <br />
WAITFOR DELAY '00:00:05' <br />
UPDATE t2 SET col2 = 'y' <br />
ROLLBACK TRAN</div></div>
<p>/* Résultat : Opération effectuée avec succès */</p>
<p>Il y a encore des choses à dire sur les deadlocks. Mais l&rsquo;idée c&rsquo;est d&rsquo;avoir ici une petite synthèse<br />
du phénomène et d&rsquo;essayer de présenter quelques pistes pour gérer au mieux les blocages et interblocages</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>TRANSACTION SQL : mode d&#8217;accès &#8211; niveau d&#8217;isolation &#8211; niveau de diagnostic</title>
		<link>https://blog.developpez.com/zinzineti/p10932/sql-server-2008/transaction_sql_mode_d_acces_niveau_d_is</link>
		<comments>https://blog.developpez.com/zinzineti/p10932/sql-server-2008/transaction_sql_mode_d_acces_niveau_d_is#comments</comments>
		<pubDate>Wed, 11 Apr 2012 18:17:15 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Une transaction SQL est caractérisée par un mode d&#8217;accès (READ ONLY ou READ WRITE),un niveau d&#8217;isolation (READ UNCOMMITED,READ COMMITED,REPEATABLE READ,SERIALIZABLE) et un niveau de diagnostic (DIAGNOSTIC SIZE).Le mode d&#8217;accès permet de préciser explicitement les opérations (lecture seule ou lecture/écriture) à réaliser sur la transaction. Le niveau d&#8217;isolation permet d&#8217;indiquer avec quel acharnement on souhaite protéger les transactions les unes des autres. Le niveau de diagnostic permet de limiter le nombre d&#8217;ereur dans la transaction. Selon [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Une transaction SQL est caractérisée par un mode d&rsquo;accès (READ ONLY ou READ WRITE),un niveau d&rsquo;isolation (READ UNCOMMITED,READ COMMITED,REPEATABLE READ,SERIALIZABLE) et un niveau de diagnostic (DIAGNOSTIC SIZE).Le mode d&rsquo;accès permet de préciser explicitement les opérations (lecture seule ou lecture/écriture) à réaliser sur la transaction. Le niveau d&rsquo;isolation permet d&rsquo;indiquer avec quel acharnement on souhaite protéger les transactions les unes des autres. Le niveau de diagnostic permet de limiter le nombre d&rsquo;ereur dans la transaction. Selon la norme SQL une transaction doit être paramétrée de la façon suivante :</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">SET [LOCAL] TRANSACTION [READ ONLY | READ WRITE] <br />
[ISOLATION LEVEL {READ COMMITTED | READ UNCOMMITTED | <br />
REPEATABLE READ | SERIALIZABLE}] <br />
[DIAGNOSTIC SIZE int]</div></div>
<p><em>LOCAL</em> : indique que le mode d&rsquo;accès et le niveau d&rsquo;isolation indiqué s&rsquo;applique à la session courante. si le mot clé LOCAL n&rsquo;est pas indiqué la transaction suivante peut changer même si on est sur la même session<br />
<em>READ ONLY</em> : indique que la transaction est une opération de lecture seule<br />
<em>READ WRITE</em> : indique que la transaction peut lire ou modifier des données dans la base<br />
<em>ISOLATION LEVEL</em> : indique le niveau de protection des transactions<br />
<em>DIAGNOSTIC SIZE int</em> : limite le nombre d&rsquo;erreur dans la transaction. plus ce nombre est élévé plus il y a consommation de ressources système. la commande GET DIAGNOSTICS permet de recupérer les messages d&rsquo;erreurs.</p>
<p><strong>SQL SERVER ne respecte pas rigoureusement cette syntaxe</strong>. Il est impossible sous SQL SERVER de préciser de façon explicite le :<br />
<strong>1) mode d&rsquo;accès (READ_ONLY ou READ_WRITE)<br />
2) niveau de DIAGNOSTIC </strong></p>
<p>Seul le niveau d&rsquo;isolation peut être explicitement indiqué sous SQL SERVER. Rappelons que les niveaux d&rsquo;isolation permettent de resoudre les problèmes de lecture sale (dirty read), lecture qui ne peut être répétée (non-repeatable read) et de lecture fantôme (phantom read). Dans ce billet nous allons examiner ces problèmes et mettre en évidence le mécanisme de verrou (lock) posé par SQL SERVER sur une table.<span id="more-102"></span></p>
<p>Dans les exemples qui vont suivre nous allons utiliser deux sessions via SQL Server Management Studio (ssms)<br />
Pour passer d&rsquo;une session à une autre j&rsquo;ai préféré la présentation ci-dessous pour plus de confort visuel.</p>
<p>Une fois les deux fenêtre ouvertes, clique droit sur l&rsquo;onglet</p>
<p><img src="http://zinzineti.ftp-developpez.com/images/session1.jpg" alt="presentation session" title="presentation session" /></p>
<p>Choisir l&rsquo;affichage verticale des sessions</p>
<p><img src="http://zinzineti.ftp-developpez.com/images/session2.jpg" alt="presentation session" title="presentation session" /></p>
<p>Voyons maintenant les différents niveaux d&rsquo;isolation.</p>
<p>=> <strong>READ COMMITED</strong> (c&rsquo;est niveau d&rsquo;isolation par défaut sous SQL SERVER) : isole la transaction des problèmes de lecture sale</p>
<p>&#8211;> <strong>Session 1</strong>  : dans la session 1, exécuter la requête de création et de remplissage de la table<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">-- Création de la table <br />
IF OBJECT_ID('ExpertSGBD') IS NOT NULL DROP TABLE ExpertSGBD <br />
CREATE TABLE ExpertSGBD (id int,prenom varchar(20),nbpoints int,date_inscription datetime) <br />
-- insertion des données dans la table <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (1,'Frédéric',17581,'20020501') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (2,'David',6704,'20020801') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (3,'Nicolas',8488,'20050101') <br />
-- vérification des données insérées <br />
SELECT * FROM ExpertSGBD <br />
&nbsp;<br />
--Démarrer dans la session 1 la transaction suivante : <br />
BEGIN TRAN <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (4,'Etienne',2408,'20100301') <br />
-- Vérifier l'insertion de la nouvelle ligne dans la session 1, remarquer que jusque là on n'a pas encore COMMITé ni ROLLBACKé la transaction &nbsp;<br />
SELECT * FROM ExpertSGBD</div></div>
<p>&#8211;> <strong>Session 2</strong> : dans la session 2, exécuter la requête suivante :<br />
&#8212;&#8212;&#8212;&#8212;-<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD</span></code></p>
<p><strong><font color="#0000ff"># Résultat session 2 : La requête ne s&rsquo;exécute pas, elle reste bloquée.<br />
<strong>## Explication</strong> : La transaction en cours d&rsquo;exécution dans la session 1 fait que SQL Server a posé un verrou (LOCK) sur la table, il est donc impossible à d&rsquo;autre session de lire les données de la table </font></strong> </p>
<p>&#8211;> <strong>Session 1</strong>  : Revenons dans la session 1 et validons la transaction en cours avec un COMMIT<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">COMMIT TRANSACTION</span></code></p>
<p>&#8211;> <strong>Session 2</strong> : Dans la fenêtre de la session 2, exécutons la requête suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 2 : La requête s&rsquo;exécute correctement et la nouvelle ligne apparaît après COMMIT (validation) dans la session 1<br />
<strong> ## Explication</strong> : après validation (COMMIT) de la transaction dans la session 1, le verrou posé par SQL SERVER sur la table est lévé et les données ainsi validées sont accessibles à toutes les sessions</strong> </font></p>
<p><strong><font color="#008000">Mais comment éviter le verrou sur la totalité des lignes de la TABLE et permettre l&rsquo;accessibilité des données initiales validées avant le démarrage de la transaction ? </font></strong><br />
<font color="#0000ff"><strong><br />
## Astuce : faire en sorte que SQL Server utilise par exemple un index et pas un <strong>Table Scan</strong> lors de la lecture des données.</strong></font></p>
<p><strong>Exemple</strong><br />
&#8212;&#8212;&#8211;</p>
<p>&#8211;> <strong>Session 1</strong>  : dans la session 1, exécuter la requête de création et de remplissage de la table<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">IF OBJECT_ID('ExpertSGBD') IS NOT NULL DROP TABLE ExpertSGBD <br />
CREATE TABLE ExpertSGBD (id int,prenom varchar(20),nbpoints int,date_inscription datetime) <br />
-- insertion des données dans la table <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (1,'Frédéric',17581,'20020501') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (2,'David',6704,'20020801') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (3,'Nicolas',8488,'20050101') <br />
-- posons un index sur la table &nbsp;<br />
CREATE INDEX IX ON ExpertSGBD (id,prenom,nbpoints,date_inscription)</div></div>
<p>&#8211;> <strong>Session 1</strong> : Démarrer depuis la session 1 la transaction suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">BEGIN TRAN <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (4,'Etienne',2408,'20100301') <br />
&nbsp;<br />
-- Vérifier l'insertion de la nouvelle ligne depuis la session 1, remarquer que jusque là on n'a pas encore COMMITé ni ROLLBACKé la transaction &nbsp;<br />
SELECT * FROM ExpertSGBD</div></div>
<p>&#8211;> <strong>Session 2</strong> : Dans la fenêtre de la session 2, exécuter la requête suivante<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p><code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WHERE ID &lt; 4</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 2 : Cette fois-ci la requête s&rsquo;exécute. Les données présentes dans la table avant le début de transaction sont affichées.<br />
## Explication : SQL Server utilise l&rsquo;index créé (INDEX SEEK) pour parcourir la table. une analyse du plan d&rsquo;exécution de la requête le montre. Par contre la nouvelle ligne insérée (non COMMITée) visible depuis la session 1 n&rsquo;est pas visible par la session 2 car l&rsquo;exécution de la requête <code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WHERE ID &lt; 5</span></code> bloque.</strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Faire un COMMIT TRANSACTION pour valider la transaction<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">COMMIT TRANSACTION</span></code></p>
<p><strong><font color="#008000">Quelles sont les limites du niveau d&rsquo;isolation READ COMMITED ? </font> </strong></p>
<p>READ COMMITED ne protège pas de la lecture non répétable, c&rsquo;est quoi la lecture non répétable ? Pour une même requête, les données affichées variées. Prenons un exemple :</p>
<p><strong>Exemple</strong><br />
&#8212;&#8212;&#8211;</p>
<p>&#8211;> <strong>Session 1</strong> : Exécuter la requête de création et de remplissage de la table<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
&#8212; table</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">IF OBJECT_ID('ExpertSGBD') IS NOT NULL DROP TABLE ExpertSGBD <br />
CREATE TABLE ExpertSGBD (id int,prenom varchar(20),nbpoints int,date_inscription datetime) <br />
-- insertion des données dans la table <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (1,'Frédéric',17581,'20020501') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (2,'David',6704,'20020801') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (3,'Nicolas',8488,'20050101')</div></div>
<p>&#8212; Exécutons dans la session 1 la requête suivante :<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WHERE nbpoints &gt; 17580 -- on a 1 ligne qui s'affiche</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 1 : On a 1 ligne affichée </strong></font></p>
<p>&#8211;> <strong>Session 2</strong> : Depuis la session 2 exécuter une requête de mise à jour :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">UPDATE ExpertSGBD &nbsp;<br />
&nbsp; &nbsp; &nbsp;SET nbpoints = 17580 <br />
WHERE id = 1</div></div>
<p><font color="#0000ff"><strong> # Résultat session 2 : Update effectué avec succès </strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Rejouons à nouveau la même requête SELECT que précedemment<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WHERE nbpoints &gt; 17580 -- on a 0 ligne qui s'affiche</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 1 : Cette fois-ci on a 0 ligne ! la requête SELECT * FROM ExpertSGBD WHERE nbpoints > 17580 n&rsquo;est donc pas repetable sous la session 1 un coup on a 1 ligne et un autre coup on a 0 ligne ! Voilà un des problèmes du niveau d&rsquo;isolation READ COMMITED </strong></font></p>
<p>=> <strong>REPEATABLE READ : protège la transaction des problèmes de lecture sale et lecture qui ne peut être répétée<br />
</strong></p>
<p>&#8212; <strong>Session 1</strong> : Exécuter la requête de création et de remplissage de la table<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
&#8212; Création de la table</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">IF OBJECT_ID('ExpertSGBD') IS NOT NULL DROP TABLE ExpertSGBD <br />
CREATE TABLE ExpertSGBD (id int,prenom varchar(20),nbpoints int,date_inscription datetime) <br />
-- insertion des données dans la table <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (1,'Frédéric',17581,'20020501') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (2,'David',6704,'20020801') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (3,'Nicolas',8488,'20050101')</div></div>
<p>&#8211;> <strong>Session 1</strong> : Démarrer depuis la session 1 la transaction suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">SET TRANSACTION ISOLATION LEVEL REPEATABLE READ <br />
BEGIN TRAN <br />
SELECT * FROM ExpertSGBD WHERE nbpoints &gt; 17580 -- on a une ligne qui qui s'affiche</div></div>
<p>&#8211;> <strong>Session 2</strong> : Depuis la session 2, mettons à jour une ligne de la table à l&rsquo;aide de la requête suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">UPDATE ExpertSGBD &nbsp;<br />
&nbsp; &nbsp; &nbsp;SET nbpoints = 17580 <br />
WHERE id = 1</div></div>
<p><font color="#0000ff"><strong> # Résultat session 2 : Impossible de mettre à jour la ligne, LOCK de la Table </strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Rejouons à nouveau dans la session 1 la requête suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WHERE nbpoints &gt; 17580 -- on a une ligne qui s'affiche</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 1 : On a toujours une ligne affichée, la requête renvoie toujours les mêmes données.<br />
## Explication : SQL SERVER a posé un verrou sur les lignes en cours de lecture, ainsi aucune modification de ces lignes n&rsquo;est possible par une autre session. Le problème de lecture qui ne peut être répétée est ainsi résolu avec le niveau d&rsquo;isolation REPEATABLE READ </strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Dans la session 1 faisons un COMMIT pour valider la transaction<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">COMMIT TRANSACTION</span></code></p>
<p><strong><font color="#008000">Quelles sont les limites du niveau d&rsquo;isolation REPEATABLE READ ? </font> </strong> REPEATABLE READ resoud le problème de lecture qui ne peut être répétée, mais pas le problème de lecture fantôme. Prenons un exemple.</p>
<p><strong>Exemple </strong><br />
&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>&#8211;> <strong>Session 1 </strong>: Exécuter la requête de création et de remplissage de la table<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
&#8212; Création de la table</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">IF OBJECT_ID('ExpertSGBD') IS NOT NULL DROP TABLE ExpertSGBD <br />
CREATE TABLE ExpertSGBD (id int,prenom varchar(20),nbpoints int,date_inscription datetime) <br />
-- insertion des données dans la table <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (1,'Frédéric',17581,'20020501') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (2,'David',6704,'20020801') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (3,'Nicolas',8488,'20050101')</div></div>
<p>&#8211;> <strong>Session 1</strong> : Démarrer depuis la session 1 la transaction suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">SET TRANSACTION ISOLATION LEVEL REPEATABLE READ <br />
BEGIN TRAN <br />
SELECT * FROM ExpertSGBD -- on a 3 lignes qui qui s'affiche</div></div>
<p>&#8211;> <strong>Session 2</strong> : Depuis la session 2, insérons une nouvelle à l&rsquo;aide de la requête suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (4,'Etienne',2408,'20100301')</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 2 : insertion effectuée avec succès depuis la session 2 </strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Rejouons dans la session 1, la requête SELECT * FROM ExpertSGBD<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD -- on a 4 lignes qui s'affiche</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 1 : Cette fois-ci on a 4 lignes ! une ligne fantôme apparaît ! le niveau d&rsquo;isolation REPEATABLE READ ne resoud pas ce problème de ligne fantôme.</strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Validons la transaction (COMMIT)<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">COMMIT TRANSACTION</span></code></p>
<p>=> <strong>SERIALIZABLE</strong> : protège la transaction des problèmes de lecture sale, de lecture qui ne peut être répétée et de lecture fantôme</p>
<p>&#8211;> <strong>Session 1</strong> : Exécuter la requête de création et de remplissage de la table<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">-- Création de la table &nbsp;<br />
IF OBJECT_ID('ExpertSGBD') IS NOT NULL DROP TABLE ExpertSGBD <br />
CREATE TABLE ExpertSGBD (id int,prenom varchar(20),nbpoints int,date_inscription datetime) <br />
-- insertion des données dans la table <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (1,'Frédéric',17581,'20020501') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (2,'David',6704,'20020801') <br />
INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (3,'Nicolas',8488,'20050101')</div></div>
<p>&#8211;> <strong>Session 1</strong> : Démarrer depuis la session 1 la transaction suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">SET TRANSACTION ISOLATION LEVEL SERIALIZABLE <br />
BEGIN TRAN <br />
SELECT * FROM ExpertSGBD -- on a 3 lignes qui qui s'affiche</div></div>
<p>&#8211;> <strong>Session 2</strong> : Depuis la session 2, insérons une nouvelle à l&rsquo;aide de la requête suivante :<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">INSERT INTO ExpertSGBD (id,prenom,nbpoints,date_inscription) VALUES (4,'Etienne',2408,'20100301')</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 2 : Impossible de faire l&rsquo;INSERT ! depuis la session 2 </strong> </font></p>
<p>&#8211;> <strong>Session 2</strong> : depuis la session 2, essayer un UDPATE<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">UPDATE ExpertSGBD &nbsp;<br />
&nbsp; &nbsp; &nbsp;SET nbpoints = 17580 <br />
WHERE id = 1</div></div>
<p><font color="#0000ff"><strong> # Résultat session 2 : Impossible de faire un UPDATE sur la table ! </strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Rejouons dans la session 1, la requête SELECT * FROM ExpertSGBD<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD</span></code></p>
<p><font color="#0000ff"><strong> # Résultat session 1 : On a toujours les mêmes données que précédemment : pas de lecture sale, pas de lecture qui ne peut être répétée, pas de lecture fantôme </strong></font></p>
<p>&#8211;> <strong>Session 1</strong> : Validons la transaction (COMMIT)<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">COMMIT TRANSACTION</span></code></p>
<p>=><strong> READ UNCOMMITED</strong><br />
Le niveau d&rsquo;isolation READ UNCOMMITED est le niveau de protection le plus bas. READ UNCOMMITED n&rsquo;assure aucune protection. Ne résoud donc aucun des problèmes d&rsquo;intégrité de données : lecture sale, lecture non repetatable,lecture fantôme. Il existe plusieurs possibilités pour positionner une transaction sur ce niveau d&rsquo;isolation : </p>
<p><strong>Exemple 1</strong> : SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</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">SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED <br />
BEGIN TRAN <br />
SELECT * FROM ExpertSGBD <br />
COMMIT TRANSACTION</div></div>
<p><strong>Exemple 2</strong> : Utilisation dans la requête du mot clé (HINT) READUNCOMMITTED<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WITH (READUNCOMMITTED)</span></code></p>
<p><strong>Exemple 3</strong> : Utilisation dans la requête du mot clé NOCLOCK<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM ExpertSGBD WITH (NOCLOCK)</span></code></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;xxx&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>On peut conclure, au travers de ces scénarii que le niveau SERIALIZABLE assure une parfaite protection (isolation) des transactions et donc l&rsquo;intégrité des données. Les transactions sont dans ce cas traitées en série au sein du SGBD. Ce mécanisme de traitement en série des transactions SQL peut nuire au performance. Et c&rsquo;est ce niveau SERIALIZABLE que la norme SQL propose comme niveau par défaut pour les SGBDs. À mon humble avis lors du développement des procédures SQL pour les applications il faut essayer de trouver l&rsquo;équilibre entre performance (niveau d&rsquo;isolation faible, donc pas de traitement en série) et intégrité (niveau d&rsquo;isolation élevé) de données.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AUTOCOMMIT ou COMMIT IMPLICITE : quelle confusion ?</title>
		<link>https://blog.developpez.com/zinzineti/p10924/sql-server-2008/autocommit_ou_commit_implicite_quelle_co</link>
		<comments>https://blog.developpez.com/zinzineti/p10924/sql-server-2008/autocommit_ou_commit_implicite_quelle_co#comments</comments>
		<pubDate>Thu, 05 Apr 2012 16:47:40 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[ORACLE]]></category>
		<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La norme SQL standard (ANSI/ISO) affirme que : 1. la première instruction SQL lancée depuis une session est considérée comme le début d&#8217;une transaction (même si le verbe BEGIN TRANSACTION n&#8217;est pas indiqué). 2. la fin de toute transaction DOIT se terminer de façon EXPLICITE par un ROLLBACK ou un COMMIT. C&#8217;est ce que dit la norme SQL à propos de la notion de début et fin d&#8217;une transaction SQL. Rappelons qu&#8217;une transaction SQL est [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La norme SQL standard (ANSI/ISO) affirme que :<br />
<strong>1.</strong> la première instruction SQL lancée depuis une session est considérée comme le début d&rsquo;une transaction (même si le verbe BEGIN TRANSACTION n&rsquo;est pas indiqué).<br />
<strong>2.</strong> la fin de toute transaction <strong>DOIT</strong> se terminer de façon <strong>EXPLICITE</strong> par un <strong>ROLLBACK</strong> ou un <strong>COMMIT</strong>.<br />
C&rsquo;est ce que dit la norme SQL à propos de la notion de début et fin d&rsquo;une transaction SQL.<br />
Rappelons qu&rsquo;une transaction SQL est une entité logique comportant une ou plusieurs instruction SQL.<br />
Par défaut SQL SERVER considère chaque instruction comme une transaction et fait des COMMITs implicites après chaque exécution : c&rsquo;est l&rsquo;AUTOCOMMIT.<br />
Par défaut ORACLE fait des commit implicites à la fin de chaque instruction DDL (CREATE, ALTER, DROP). Notons que sur ce point ORACLE est plus proche de la norme que SQL SERVER.<br />
Ce que je ne comprends pas c&rsquo;est la confusion que crée MS SQL SERVER autour de la définition de l&rsquo;option AUTOCOMMIT. De quoi s&rsquo;agit-il exactement ?<span id="more-101"></span><br />
D&rsquo;après la documentation officielle de MS SQL SERVER :<br />
Version originale<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<blockquote><p>SET IMPLICIT_TRANSACTIONS { ON | OFF }<br />
Sets implicit transaction mode for the connection.<br />
When ON, SET IMPLICIT_TRANSACTIONS sets the connection into implicit transaction mode.<br />
When OFF, it returns the connection to autocommit transaction mode.</p></blockquote>
<p>Traduction en français<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<blockquote><p>SET IMPLICIT_TRANSACTIONS { ON | OFF }<br />
Définit le mode de transaction implicite pour la connexion.<br />
Si sa valeur est ON, SET IMPLICIT_TRANSACTIONS met la connexion en mode de transaction implicite.<br />
Si la valeur est OFF, la connexion est remise en mode de validation automatique.</p></blockquote>
<p>D&rsquo;après ce qui est écrit dans la documentation officielle :<br />
<strong>SET IMPLICIT_TRANSACTIONS OFF = AUTOCOMMIT (validation automatique).<br />
Mais le problème c&rsquo;est que si IMPLICIT_&#8230;. est OFF on peut penser qu&rsquo;on est en mode EXPLICIT_&#8230; et en EXPLICIT_&#8230; ce n&rsquo;est plus de l&rsquo;AUTOCOMMIT ! </strong></p>
<p>=> <strong>Sous SQL SERVER</strong><br />
D&rsquo;abord comment identifier l&rsquo;option SET IMPLICIT_TRANSACTIONS de ma session ?</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 CASE WHEN (@@OPTIONS &amp; 2 = 2) THEN &nbsp;'IMPLICIT_TRANSACTIONS ON' <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ELSE 'IMPLICIT_TRANSACTIONS OFF' <br />
&nbsp; &nbsp; &nbsp; &nbsp; END 'IMPLICIT_TRANSACTIONS'</div></div>
<p><strong>Exemple avec SET IMPLICIT_TRANSACTIONS OFF</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
Session 1<br />
&#8212;&#8212;&#8212;</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">IF OBJECT_ID(N't1', N'U') IS NOT NULL DROP TABLE t1; <br />
SET IMPLICIT_TRANSACTIONS OFF <br />
CREATE TABLE t1(c INT); <br />
INSERT INTO t1 VALUES (1);</div></div>
<p>Session 2<br />
&#8212;&#8212;&#8212;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM t1</span></code></p>
<p><strong>La session 2 affiche bien les données de la table t1</strong></p>
<p><strong>Exemple avec SET IMPLICIT_TRANSACTIONS ON</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
Session 1<br />
&#8212;&#8212;&#8212;</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">IF OBJECT_ID(N't1', N'U') IS NOT NULL DROP TABLE t1; <br />
SET IMPLICIT_TRANSACTIONS ON <br />
CREATE TABLE t1(c INT); <br />
INSERT INTO t1 VALUES (1);</div></div>
<p>Session 2<br />
&#8212;&#8212;&#8212;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM t1</span></code></p>
<p><strong>Impossible de lire les données de la table t1 depuis la session 2, puisque la transaction n&rsquo;est pas encore validée (commit) par la session 1</strong></p>
<p>=> <strong>Sous ORACLE </strong><br />
D&rsquo;abord comment identifier l&rsquo;option AUTOCOMMIT de ma session ?</p>
<p><code class="codecolorer text default"><span class="text">SQL&gt; SHOW AUTOCOMMIT;</span></code></p>
<p><strong>Exemple avec AUTOCOMMIT ON</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
Session 1<br />
&#8212;&#8212;&#8212;</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">SET AUTOCOMMIT ON <br />
CREATE TABLE t1(c INT); <br />
INSERT INTO t1 VALUES (1);</div></div>
<p>Session 2<br />
&#8212;&#8212;&#8212;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM t1</span></code><br />
<strong>La session 2 affiche bien les données de la table t1</strong></p>
<p><strong>Exemple avec AUTOCOMMIT OFF</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
Session 1<br />
&#8212;&#8212;&#8212;</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">SET AUTOCOMMIT OFF <br />
CREATE TABLE t1(c INT); <br />
INSERT INTO t1 VALUES (1);</div></div>
<p>Session 2<br />
&#8212;&#8212;&#8212;<br />
<code class="codecolorer text default"><span class="text">SELECT * FROM t1</span></code><br />
<strong>Impossible de lire les données de la table t1 depuis la session 2, puisque la transaction n&rsquo;est pas encore validée (commit) par la session 1</strong></p>
<p>Pour conclure notons que pour MS SQL SERVER SET IMPLICIT_TRANSACTIONS OFF = AUTOCOMMIT. À mon humble avis, MS SQL SERVER devrait plutôt mettre <strong>SET IMPLICIT_TRANSACTIONS ON = AUTOCOMMIT</strong></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>SAVEPOINT vs SAVE TRANSACTION</title>
		<link>https://blog.developpez.com/zinzineti/p10871/sql-server-2008/savepoint_vs_save_transaction</link>
		<comments>https://blog.developpez.com/zinzineti/p10871/sql-server-2008/savepoint_vs_save_transaction#comments</comments>
		<pubDate>Fri, 23 Mar 2012 17:20:16 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La norme SQL propose un moyen de poser des points de restaurations dans une transaction : les SAVEPOINTs. L&#8217;idée c&#8217;est de pouvoir revenir à une étape donnée dans la transaction. Selon la norme SQL la synthaxe pour créer un SAVEPOINT est la suivante :SAVEPOINT savepoint_name et pour revenir en arrière :ROLLBACK TO SAVEPOINT savepoint_name . La commande SAVEPOINT n&#8217;existe pas sous MS SQL SERVER mais une commande similaire exite : SAVE { TRAN &#124; TRANSACTION [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La norme SQL propose un moyen de poser des points de restaurations dans une transaction : les <strong>SAVEPOINTs</strong>. L&rsquo;idée c&rsquo;est de pouvoir revenir à une étape donnée dans la transaction. Selon la norme SQL la synthaxe pour créer un SAVEPOINT est la suivante :<code class="codecolorer text default"><span class="text">SAVEPOINT savepoint_name</span></code> et pour revenir en arrière :<code class="codecolorer text default"><span class="text">ROLLBACK TO SAVEPOINT savepoint_name</span></code> . La commande SAVEPOINT n&rsquo;existe pas sous MS SQL SERVER mais une commande similaire exite : <code class="codecolorer text default"><span class="text">SAVE { TRAN | TRANSACTION } { savepoint_name | @savepoint_variable }</span></code> et pour revenir en arrière : <code class="codecolorer text default"><span class="text">ROLLBACK { TRAN | TRANSACTION } [ transaction_name | @tran_name_variable | savepoint_name | @savepoint_variable ]</span></code> </p>
<p>La norme SQL:2003 introduit la commande <code class="codecolorer text default"><span class="text">RELEASE SAVEPOINT savepoint_name</span></code>    qui permet de détruire un savepoint. Son équivalent SQL SERVER n&rsquo;existe pas. MS SQL SERVER supprime les points de restauration automatiquement à la fin des transaction (COMMIT ou ROLLACK)<br />
<span id="more-100"></span></p>
<p>=> <strong>SAVEPOINT /ROLLBACK TO SAVEPOINT</strong></p>
<p>&#8211;> Avec PostgreSQL</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">BEGIN; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('1'); <br />
&nbsp; &nbsp; SAVEPOINT savepoint1; -- création du savepoint1 &nbsp;<br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('2'); <br />
&nbsp; &nbsp; SAVEPOINT savepoint2; -- création du savepoint2 <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('3'); <br />
&nbsp; &nbsp; ROLLBACK TO SAVEPOINT savepoint1; -- ROLLBACK TO savepoint1 &nbsp;<br />
COMMIT; <br />
&nbsp;<br />
SELECT * FROM table1; <br />
&nbsp;<br />
/*** résultat ***/ <br />
&nbsp;<br />
col <br />
--- <br />
1</div></div>
<p>&#8212;> Avec MS SQL SERVER</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">DROP TABLE table1; <br />
CREATE TABLE table1 (col CHAR(1)); <br />
BEGIN TRAN Transaction_Principale <br />
&nbsp; INSERT INTO table1 VALUES ('1') <br />
&nbsp; SAVE TRAN savepoint1 &nbsp;-- création du savepoint1 &nbsp;<br />
&nbsp; BEGIN TRAN Transaction_Imbriquée <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('2') <br />
&nbsp; &nbsp; SAVE TRAN savepoint2 -- création du savepoint2 <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('3'); <br />
&nbsp; ROLLBACK TRAN savepoint1 -- ROLLBACK TO savepoint1 &nbsp;<br />
COMMIT ; <br />
&nbsp;<br />
SELECT * FROM table1 <br />
&nbsp;<br />
/*** résultat ***/ <br />
&nbsp;<br />
col <br />
--- <br />
1</div></div>
<p>=> <strong>SAVEPOINTS avec les mêmes noms</strong><br />
La norme SQL stipule que lorsqu&rsquo;on crée un savepoint avec le même nom qu&rsquo;un autre savepoint existant alors ce dernier doit être automatiquement détruit. le plus récent savepoint remplace donc l&rsquo;ancien ayant le même nom.</p>
<p>&#8211;> Avec PostgreSQL</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">DROP TABLE table1; <br />
CREATE TABLE table1 (col CHAR(1)); <br />
BEGIN; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('1'); <br />
&nbsp; &nbsp; SAVEPOINT savepoint1; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('2'); <br />
&nbsp; &nbsp; SAVEPOINT savepoint1; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('3'); <br />
&nbsp; &nbsp; ROLLBACK TO SAVEPOINT savepoint1; <br />
COMMIT; <br />
&nbsp;<br />
SELECT * FROM table1; <br />
&nbsp;<br />
/*** résultat ***/ <br />
&nbsp;<br />
col <br />
--- <br />
1 <br />
2</div></div>
<p>&#8211;> Avec MS SQL SERVER</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">DROP TABLE table1; <br />
CREATE TABLE table1 (col CHAR(1)); <br />
BEGIN TRAN Transaction_Principale <br />
&nbsp; INSERT INTO table1 VALUES ('1') <br />
&nbsp; SAVE TRAN savepoint1 &nbsp;-- création du savepoint1 &nbsp;<br />
&nbsp; BEGIN TRAN Transaction_Imbriquée <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('2') <br />
&nbsp; &nbsp; SAVE TRAN savepoint1 -- création du savepoint2 <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('3') <br />
&nbsp; ROLLBACK TRAN savepoint1 -- ROLLBACK TO savepoint1 &nbsp;<br />
COMMIT ; <br />
&nbsp;<br />
SELECT * FROM table1 <br />
&nbsp;<br />
/*** résultat ***/ <br />
&nbsp;<br />
col <br />
--- <br />
1 <br />
2</div></div>
<p>=> <strong>RELEASE SAVEPOINT</strong></p>
<p>&#8211;> Avec PostgreSQL</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">DROP TABLE table1; <br />
CREATE TABLE table1 (col CHAR(1)); <br />
BEGIN; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('1'); <br />
&nbsp; &nbsp; SAVEPOINT savepoint1; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('2'); <br />
&nbsp; &nbsp; SAVEPOINT savepoint2; <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('3'); <br />
&nbsp; &nbsp; RELEASE SAVEPOINT savepoint1; <br />
COMMIT; <br />
&nbsp;<br />
SELECT * FROM table1; <br />
&nbsp;<br />
/*** résultat ***/ <br />
&nbsp;<br />
col <br />
--- <br />
1 <br />
2 <br />
3</div></div>
<p>&#8211;> Avec MS SQL SERVER</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">DELETE FROM table1 <br />
BEGIN TRAN Transaction_Principale <br />
&nbsp; INSERT INTO table1 VALUES ('1') <br />
&nbsp; SAVE TRAN savepoint1 &nbsp;-- création du savepoint1 &nbsp;<br />
&nbsp; BEGIN TRAN Transaction_Imbriquée <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('2') <br />
&nbsp; &nbsp; SAVE TRAN savepoint2 -- création du savepoint2 <br />
&nbsp; &nbsp; INSERT INTO table1 VALUES ('3') <br />
&nbsp; COMMIT TRAN savepoint1 -- ROLLBACK TO savepoint1 &nbsp;<br />
COMMIT ; <br />
&nbsp;<br />
SELECT * FROM table1 <br />
&nbsp;<br />
/*** résultat ***/ <br />
&nbsp;<br />
col <br />
--- <br />
1 <br />
2 <br />
3</div></div>
<p>Comme MS SQL SERVER, ORACLE ne supporte pas non plus la commande standard <strong>RELEASE SAVEPOINT</strong>. Notons que parmi les SGBDs les plus connus du marché, MS SQL SERVER est le seul à ne pas implémenter la commande  <code class="codecolorer text default"><span class="text">SAVEPOINT &nbsp;savepoint_name</span></code>. IBM DB2, ORACLE, PostGreSQL et &laquo;&nbsp;MySQL&nbsp;&raquo; ont tous implémenté la commande SAVEPOINT.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
Etienne ZINZINDOHOUE<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modeles de licences pour SQL SERVER 2012</title>
		<link>https://blog.developpez.com/zinzineti/p10848/sql-server-2012/modele_de_licences_pour_sql_server_2012</link>
		<comments>https://blog.developpez.com/zinzineti/p10848/sql-server-2012/modele_de_licences_pour_sql_server_2012#comments</comments>
		<pubDate>Sat, 17 Mar 2012 09:01:38 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2012]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[&#8211;> Vidéo 5 minutes pour comprendre les modèles de licences pour SQL SERVER 2012 &#8211;> PDF Modèles de licences pour SQL SERVER 2012]]></description>
				<content:encoded><![CDATA[<p>&#8211;> Vidéo <a href="http://www.microsoft.com/fr-fr/showcase/details.aspx?uuid=ff7775c8-fe1f-472f-89f1-400a3d3d4dbe"> 5 minutes pour comprendre les modèles de licences pour SQL SERVER 2012</a></p>
<p>&#8211;> PDF <a href="http://view.atdmt.com/action/frmfrm_FY12H2SQLServer2012DescriptionLicenceBT_1">Modèles de licences pour SQL SERVER 2012 </a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Curseurs ouverts</title>
		<link>https://blog.developpez.com/zinzineti/p10824/sql-server-2008/curseurs_ouverts</link>
		<comments>https://blog.developpez.com/zinzineti/p10824/sql-server-2008/curseurs_ouverts#comments</comments>
		<pubDate>Mon, 12 Mar 2012 19:51:57 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Les curseurs font partie intégrante de la norme SQL. Ils sont utilisés dans les SGBDRs pour réaliser des traitements ligne par ligne. Le temps de traitement des transactions SQL utilisant des curseurs dépend du SGBDR, de la qualité/quantité des données traitées, de l&#8217;écriture de la transaction SQL contenant le curseur, &#8230;. Un curseur utilisé et qui n&#8217;est pas fermé (ne se termine pas par CLOSE nomCurseur et DEALLOCATE nomCurseur) aura des incidences sur la performance [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Les curseurs font partie intégrante de la norme SQL. Ils sont utilisés dans les SGBDRs pour réaliser des traitements ligne par ligne. Le temps de traitement des transactions SQL utilisant des curseurs dépend du SGBDR, de la qualité/quantité des données traitées, de l&rsquo;écriture de la transaction SQL contenant le curseur, &#8230;.<br />
Un curseur utilisé et qui n&rsquo;est pas fermé (ne se termine pas par CLOSE nomCurseur et DEALLOCATE nomCurseur) aura des incidences sur la performance du serveur de base de données.<span id="more-99"></span> </p>
<p>=> Liste des curseurs ouverts pour toutes les sessions</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 c.session_id <br />
,s.login_name <br />
,s.host_name <br />
,s.program_name <br />
,c.creation_time <br />
,c.name <br />
,c.is_open <br />
,c.is_close_on_commit <br />
,c.worker_time <br />
,c.dormant_duration <br />
,t.text as sql_text <br />
FROM sys.dm_exec_cursors(0)as c &nbsp;<br />
INNER JOIN sys.dm_exec_sessions as s ON c.session_id = s.session_id &nbsp;<br />
CROSS APPLY sys.dm_exec_sql_text(c.sql_handle) t</div></div>
<p>=> Pour fermer les curseurs : Solution brutale<br />
<code class="codecolorer text default"><span class="text">KILL c.session_id</span></code><br />
Exemple<br />
&#8212;&#8212;&#8211;<br />
<code class="codecolorer text default"><span class="text">KILL 52</span></code></p>
<p>=> Pour fermer les curseurs : Solution durable</p>
<p>Ajouter <strong>CLOSE nomCurseur et DEALLOCATE nomCurseur</strong> dans les procédures concernées</p>
<p>L&rsquo;option CURSOR_CLOSE_ON_COMMIT (pour la session ou pour la base de donnée) est sensée résoudre ce genre de problème selon les recommandations de la norme ISO, mais la réalité est tout autre. </p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
Etienne ZINZINDOHOUE</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FOREIGN KEYs non indexés</title>
		<link>https://blog.developpez.com/zinzineti/p10823/sql-server-2008/foreign_key_non_indexes</link>
		<comments>https://blog.developpez.com/zinzineti/p10823/sql-server-2008/foreign_key_non_indexes#comments</comments>
		<pubDate>Mon, 12 Mar 2012 18:33:57 +0000</pubDate>
		<dc:creator><![CDATA[zinzineti]]></dc:creator>
				<category><![CDATA[SQL SERVER 2008]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Il est souvent recommandé d&#8217;indexer les clés étrangères (FK). Cette opération d&#8217;indexation ne doit pas se faire de façon mécanique. Elle devrait passer par les phases d&#8217;analyse, de création et de test. Mais avant comment identifier les FKs non indexés ? SELECT &#160;a.TABLE_SCHEMA,a.TABLE_NAME, b.COLUMN_NAME, b.CONSTRAINT_NAME,a.IS_DEFERRABLE,a.INITIALLY_DEFERRED FROM &#160; &#160;INFORMATION_SCHEMA.TABLE_CONSTRAINTS a &#160; &#160; &#160; INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE b ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME WHERE &#160; a.CONSTRAINT_TYPE = 'FOREIGN KEY' --AND &#160;a.TABLE_NAME = 'Commandes' /* pour une table specifique [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Il est souvent recommandé d&rsquo;indexer les clés étrangères (FK). Cette opération d&rsquo;indexation ne doit pas se faire de façon mécanique. Elle devrait passer par les phases d&rsquo;analyse, de création et de test. Mais avant comment identifier les FKs non indexés ?<span id="more-98"></span></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 &nbsp;a.TABLE_SCHEMA,a.TABLE_NAME, b.COLUMN_NAME, b.CONSTRAINT_NAME,a.IS_DEFERRABLE,a.INITIALLY_DEFERRED <br />
FROM &nbsp; &nbsp;INFORMATION_SCHEMA.TABLE_CONSTRAINTS a &nbsp;<br />
&nbsp; &nbsp; INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE b ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME <br />
WHERE &nbsp; a.CONSTRAINT_TYPE = 'FOREIGN KEY' <br />
--AND &nbsp;a.TABLE_NAME = 'Commandes' /* pour une table specifique */ <br />
AND a.TABLE_NAME + '.' + b.COLUMN_NAME NOT IN ( &nbsp;<br />
SELECT o.name +'.'+c.name <br />
FROM &nbsp;sys.objects o &nbsp; &nbsp; <br />
&nbsp; &nbsp; INNER JOIN sys.indexes i ON i.object_id = o.object_id &nbsp;<br />
&nbsp; &nbsp; INNER JOIN &nbsp;sys.columns c ON o.object_id = c.object_id &nbsp;<br />
&nbsp; &nbsp; INNER JOIN sys.index_columns ic ON ic.object_id = o.object_id AND i.index_id = ic.index_id &nbsp;AND ic.column_id = c.column_id &nbsp;<br />
&nbsp; &nbsp; WHERE &nbsp;o.type in ('U') &nbsp;<br />
)</div></div>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Etienne ZINZINDOHOUE</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
