<?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>Oracle - Concepts et Exemples &#187; restart</title>
	<atom:link href="https://blog.developpez.com/pachot/tag/restart/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/pachot</link>
	<description>Les fonctionalités et concepts d&#039;Oracle à partir de traductions et de démos</description>
	<lastBuildDate>Sun, 03 Apr 2016 20:36:21 +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>Ecritures cohérentes &#8211; observation d&#8217;un redémarrage, par Tom Kyte (2ème partie)</title>
		<link>https://blog.developpez.com/pachot/tk_consistent_write_2/</link>
		<comments>https://blog.developpez.com/pachot/tk_consistent_write_2/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 18:32:40 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Tom Kyte]]></category>
		<category><![CDATA[restart]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article est la traduction d&#8217;un article de Tom Kyte sur son blog (L&#8217;article original en anglais se trouve ici). Il est conseillé lire préalablement la première partie: Ecritures cohérentes, par Tom Kyte (1ère partie) Voir un redémarrage d&#8217;une requête &#8230; <a href="https://blog.developpez.com/pachot/tk_consistent_write_2/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<blockquote><p><ins>Cet article est la traduction d&rsquo;un article de Tom Kyte sur son blog (L&rsquo;article original en anglais se trouve <a href="http://tkyte.blogspot.com/2005/08/part-ii-seeing-restart.html">ici</a>).<br />
<br />
</ins><br />
Il est conseillé lire préalablement la première partie:
<ul>
<li><a href="http://blog.developpez.com/pachot/p9043/auteurs/tom-kyte/tk-consistent-write/">Ecritures cohérentes, par Tom Kyte (1ère partie)</a></li>
</ul>
</blockquote>
<p>Voir un redémarrage d&rsquo;une requête <i>update</i> est plus plus facile qu&rsquo;on ne pense.<br />
En fait, nous allons même en voir un avec une simple table d&rsquo;une seule ligne.<br />
<span id="more-34"></span><br />
Voici la table que nous allons utiliser pour notre test:</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">ops$tkyte@ORA10G&amp;gt; create table t ( x int, y int ); <br />
Table created. <br />
&nbsp;<br />
ops$tkyte@ORA10G&amp;gt; insert into t values ( 1, 1 ); <br />
1 row created. <br />
&nbsp;<br />
ops$tkyte@ORA10G&amp;gt; commit; <br />
Commit complete.</div></div>
<p>Pour observer le <em>restart</em>, nous avons juste besoin d&rsquo;un <em>trigger</em> qui va afficher des informations. Nous allons utiliser un trigger BEFORE UPDATE FOR EACH ROW qui va simplement afficher l&rsquo;ancienne et la nouvelle valeur de la ligne lors d&rsquo;un  update.</p>
<pre>ops$tkyte@ORA10G&gt; create or replace trigger t_bufer
  2  before update on t for each row
  3  begin
  4          dbms_output.put_line
  5          ( 'old.x = ' || :old.x ||
  6            ', old.y = ' || :old.y );
  7          dbms_output.put_line
  8          ( 'new.x = ' || :new.x ||
  9            ', new.y = ' || :new.y );
10  end;
11  /
Trigger created.</pre>
<p>Et maintenant nous faisons un update sur la ligne:</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">ops$tkyte@ORA10G&amp;gt; set serveroutput on <br />
ops$tkyte@ORA10G&amp;gt; update t set x = x+1; <br />
old.x = 1, old.y = 1 <br />
new.x = 2, new.y = 1 <br />
1 row updated.</div></div>
<p>jusqu&rsquo;ici, tout ce passe comme on s&rsquo;y attend: le trigger s&rsquo;est déclenché une fois, et nous voyons les anciennes et nouvelles valeurs. Remarquez que nous n&rsquo;avons pas encore fait de <em>commit</em>, la ligne est toujours vérouillée. Dans une autre session, nous allons faire l&rsquo;update suivant:</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">ops$tkyte@ORA10G&amp;gt; set serveroutput on <br />
ops$tkyte@ORA10G&amp;gt; update t set x = x+1 where x &amp;gt; 0;</div></div>
<p>La requête se bloque tout de suite, évidemment, puisque la première session a verrouillé la ligne. Si nous retournons dans la première session, pour faire un commit, voici ce qu&rsquo;affiche la deuxième session (j&rsquo;ai remis l&rsquo;<em>update</em> pour que ça soit plus clair)</p>
<pre>ops$tkyte@ORA10G&gt; update t set x = x+1 where x &gt; 0;
old.x = 1, old.y = 1
new.x = 2, new.y = 1
old.x = 2, old.y = 1
new.x = 3, new.y = 1
1 row updated.</pre>
<p>Comme vous pouvez le voir, le <em>trigger</em> a vu deux version de la ligne ici. Le <em>trigger</em> sur la ligne s&rsquo;est déclenché deux fois:
<ul>
<li>Une première fois avec la version d&rsquo;origine de la ligne, et les nouvelles valeurs calculées par l&rsquo;update</li>
<li>et une deuxième fois avec la version finale de la ligne telle qu&rsquo;elle a réellement été modifiée.</li>
</ul>
<p>Du fait que c&rsquo;est un trigger BEFORE FOR EACH ROW, Oracle a vu la version cohérente (<em>read-consistent</em>) de notre ligne et la mise à jour que nous souhaitons y faire. Mais c&rsquo;est après le déclenchement du trigger BEFORE FOR EACH ROW qu&rsquo; Oracle a récupéré le block en mode courant (<em>current mode</em>) pour y faire la mise à jour. Oracle doit attendre la fin du déclenchement du trigger parce que le trigger peut modifier les valeurs <strong>:new</strong>. Donc, Oracle ne peut modifier le bloc qu&rsquo;une fois que le trigger ait fini de s&rsquo;exécuter, et cela peut prendre du temps. Vu qu&rsquo;un bloc ne peut être pris en mode courant que par une seule session à la fois, Oracle doit limiter le temps passé dans ce mode.</p>
<p>Donc après que le trigger se soit exécuté, Oracle prends le bloc en mode courant et s&rsquo;aperçoit que la colonne X, qui a été utilisée pour trouver la ligne, n&rsquo;a plus la même valeur. Et comme X, qui a été utilisé pour trouver cette ligne, a été modifiée, alors la base de données décide de redémarrer notre requête.</p>
<p>Notez que le fait que la valeur de X soit passée de 1 à 2 ne fait pas sortir la ligne du périmètre de la requête. Elle va quand même être touchée par notre update. C&rsquo;est plutôt le fait que X ait été utilisé pour trouver la ligne, et que la valeur en lecture cohérente (ici 1) soit différente de la valeur en lecture courante (ici 2). Et ensuite, lors du <em>restart</em>, le trigger voit la valeur X=2 (qui vient de la modification faite par l&rsquo;autre session) comme valeur de <strong>:old</strong> et la valeur X=3 pour <strong>:new</strong></p>
<p>Donc cela prouve qu&rsquo;un <em>update restart</em> a eu lieu. Il a fallu un trigger pour le voir, sinon ils sont en généralement indétectables. Cela ne veut pas dire qu&rsquo;on ne peut pas voir d&rsquo;autres symptômes, comme un gros update qui doit faire un <em>rollback</em> de toutes les modifications effectuées lorsqu&rsquo;il a découvert qu&rsquo;une ligne provoqué le <em>restart</em>. Cela veut juste dire qu&rsquo;il est très difficile de pouvoir affirmer que ce type de symptôme vient du <em>restart</em>.</p>
<p>Il y a une autre chose intéressante, c&rsquo;est que les <em>triggers</em> eux-mêmes peuvent être la cause d&rsquo;un restart, même si la requête en elle-même ne le demande pas. Normalement, c&rsquo;est les colonnes qui sont utilisées dans la clause WHERE d&rsquo;un UPDATE ou DELETE qui sont utilisées pour déterminer si les modifications nécessitent un redémarrage de la requête. Oracle va faire une lecture en <em>consistent read</em> et lorsqu&rsquo;il prends le bloc en <em>current mode</em>, il va redémarrer la requête si l&rsquo;une de ces colonnes a été modifiée. Normalement, les autres colonnes ne sont pas comparées. Par exemple, si nous ré-exécutons la l&rsquo;exemple précédant en mettant WHERE Y&gt;0 pour trouver la ligne au lieu de X&gt;0 :</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">ops$tkyte@ORA10G&amp;gt; update t set x = x+1 where y &amp;gt; 0; <br />
old.x = 1, old.y = 1 <br />
new.x = 2, new.y = 1 <br />
old.x = 2, old.y = 1 <br />
new.x = 3, new.y = 1 <br />
1 row updated.</div></div>
<p>On peut se demander pourquoi Oracle encore  déclenché le trigger deux fois alors qu&rsquo;il regardait la valeur de Y. Et on pourrait même croire que toutes les colonnes de la ligne sont examinées. Comme on peut le voir, ici on a eu un update restart alors qu&rsquo;on filtrait les lignes avec Y&gt;0 et qu&rsquo;on a jamais modifié Y.</p>
<p>Mais si on recrée le trigger en affichant juste un message &lsquo;<em>fired</em>&lsquo; pour dire qu&rsquo;il a été déclanché, sans faire référence à <strong>:new</strong> et <strong>:old</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">ops$tkyte@ORA10G&amp;gt; create or replace trigger t_bufer <br />
&nbsp; 2 &nbsp;before update on t for each row <br />
&nbsp; 3 &nbsp;begin <br />
&nbsp; 4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dbms_output.put_line( 'fired' ); <br />
&nbsp; 5 &nbsp;end; <br />
&nbsp; 6 &nbsp;/ <br />
Trigger created. <br />
&nbsp;<br />
ops$tkyte@ORA10G&amp;gt; update t set x = x+1; <br />
fired <br />
1 row updated.</div></div>
<p>et que l&rsquo;on va à nouveau dans la deuxième session pour exécuter l&rsquo;update, on voit qu&rsquo;il bloque, bien sûr. Et après avoir fait le commit sur la première session, la deuxième session se débloque et voici ce qu&rsquo;elle affiche:</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">ops$tkyte@ORA10G&amp;gt; update t set x = x+1 where y &amp;gt; 0; <br />
fired <br />
1 row updated.</div></div>
<p>Le trigger ne s&rsquo;est déclenché qu&rsquo;une seule fois, pas deux.</p>
<p>Cela montre que les valeurs des colonnes référencées par :new et :old dans le trigger sont aussi utilisées par Oracle pour vérifier s&rsquo;il faut faire un restart.<br />
Lorsque le trigger référencait :new.X et :old.X alors les valeurs cohérentes et courantes de X ont été comparées. Et cela a entraîner un restart. Mais lorsqu&rsquo;on a enlevé ces références, le restart n&rsquo;a plus eu lieu.</p>
<p>La règle est que c&rsquo;est l&rsquo;ensemble des colonnes utilisées dans la clause WHERE, plus les colonnes référencées dans les triggers ligne (<em>row trigger</em>) qui sont comparées. La version cohérente et la version courante de la ligne vont être comparées, et si une de ces colonnes a changé, alors la requête va redémarrer.</p>
<p>A noter que cela peut aider à comprendre pourquoi un trigger AFTER FOR EACH ROW est plus performant qu&rsquo;un trigger BEFORE FOR EACH ROW. Le trigger AFTER n&rsquo;a pas les memes conséquences. Ce qui nous amène à la question &lsquo;En quoi est-ce que ce comportement interne nous concerne ?&rsquo;.</p>
<p>A suivre&#8230;</p>
<blockquote><p><ins>La troisième partie sera traduite prochainement:
<ul>
<li><a href="http://blog.developpez.com/pachot/p9070/auteurs/tom-kyte/tk-consistent-write-3/">Ecritures cohérentes &#8211; conséquences pour le développeur, par Tom Kyte</a></li>
</ul>
<p></ins></p></blockquote>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
