<?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; Jonathan Lewis</title>
	<atom:link href="https://blog.developpez.com/pachot/category/traductions/jonathan-lewis/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>Histogrammes et bind variables, par Jonathan Lewis</title>
		<link>https://blog.developpez.com/pachot/jl_philosophy_1/</link>
		<comments>https://blog.developpez.com/pachot/jl_philosophy_1/#comments</comments>
		<pubDate>Fri, 22 Jun 2012 20:46:19 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article est la traduction d&#8217;un article de Jonathan Lewis publié sur son blog. L&#8217;article original en anglais se trouve ici Sur Oracle, certains concepts sont si fondamentaux qu&#8217;on doit toujours les avoir en tête à chaque fois qu&#8217;on veut &#8230; <a href="https://blog.developpez.com/pachot/jl_philosophy_1/">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 Jonathan Lewis publié sur son blog. L&rsquo;article original en anglais se trouve <a href="http://jonathanlewis.wordpress.com/2009/05/06/philosophy-1/">ici</a></ins></p></blockquote>
<p>Sur Oracle, certains concepts sont si fondamentaux qu&rsquo;on doit toujours les avoir en tête à chaque fois qu&rsquo;on veut étudier un problème de performance. Et voici l&rsquo;un d&rsquo;eux:</p>
<p><strong>Les histogrammes et les <em>bind variables</em> existent pour des raison diamétralement opposées: sans y prêter garde, ils ne fonctionneront pas bien ensemble.</strong><br />
</p>
<p>Vous utilisez des <em>bind variables</em> parce que vous voulez que tout le monde partage le même plan d&rsquo;exécution pour une requête SQL qui va être utilisé fréquemment. Tout le monde va faire la même charge de travail avec (charge normalement faible). Son plan d&rsquo;exécution sera optimal pour tout le monde. Et vous ne voulez pas ré-optimiser cette requête à chaque fois, car cette réoptimisation utiliserait à elle seule plus de ressources qu&rsquo;il n&rsquo;en faut ensuite pour l&rsquo;exécuter.</p>
<p>En général on utilise beaucoup les <em>bind variables</em> lorsqu&rsquo;on est en transactionnel (<em>OLTP</em>) &#8211; sauf quelques cas particuliers où on préférera des valeurs littérales.<br />
</p>
<p>Et vous créez des histogrammes pour des requêtes qui, mêmes si elles sont similaires, vont faire un travail très différent les unes des autres. Elles ont besoin de plans d&rsquo;exécution différents. Et de toute façon le travail d&rsquo;optimisation est négligeable par rapport au travail d&rsquo;exécution de la requête. Alors que si on utilise un plan d&rsquo;exécution qui n&rsquo;est pas optimal, on peut se retrouver à gaspiller beaucoup de ressources.</p>
<p>En général, on a besoin des histogrammes en <em>datawarehouse</em>, en BI, où les requêtes peuvent être très grosses et coûteuses.</p>
<p>
C&rsquo;est là qu&rsquo;est la contradiction: on a une technologie qui est censée nous donner un seul plan d&rsquo;exécution partagé par tout le monde, et une autre qui elle est censée trouver pour chacun le plan qui lui convient le mieux.<br />
</p>
<p>Gardez celà en mémoire, et vous vous rappellerez qu&rsquo;il faut être très prudent lorsqu&rsquo;on met des histogrammes sur une base transactionnelle (<em>OLTP</em>) et qu&rsquo;il ne faut pas non plus transformer absolument toutes les valeurs littérales en <em>bind variables</em>.</p>
<blockquote><p><ins>A noter les commentaires de Doug Burns et Hemant K Chitale sur le fait qu&rsquo;en 10g Oracle collecte par défaut des histogrammes avec la méthode &lsquo;FOR ALL COLUMNS SIZE AUTO&rsquo; de dbms_stats.</ins></p></blockquote>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clustering Factor, Jonathan Lewis traduit par Mohamed Houri</title>
		<link>https://blog.developpez.com/pachot/clustering_factor_jonathan_lewis_traduit/</link>
		<comments>https://blog.developpez.com/pachot/clustering_factor_jonathan_lewis_traduit/#comments</comments>
		<pubDate>Mon, 23 May 2011 22:36:01 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Mohamed Houri a traduit un chapitre de Jonathan Lewis sur le Clustering Factor qui est si important dans le coùt d&#8217;accès à une table via un index. Voici le lien de la traduction en français: http://jonathanlewis.files.wordpress.com/2011/05/le-clustering-factor.pdf Jonathan Lewis a mis &#8230; <a href="https://blog.developpez.com/pachot/clustering_factor_jonathan_lewis_traduit/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Mohamed Houri a traduit un chapitre de Jonathan Lewis sur le Clustering Factor qui est si important dans le coùt d&rsquo;accès à une table via un index.<br />
Voici le lien de la traduction en français: <a href="http://jonathanlewis.files.wordpress.com/2011/05/le-clustering-factor.pdf">http://jonathanlewis.files.wordpress.com/2011/05/le-clustering-factor.pdf</a></p>
<p>Jonathan Lewis a mis les liens de l&rsquo;article original et de la traduction sur son <a href="http://jonathanlewis.wordpress.com/2011/05/19/clustering_factor/">blog</a>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Redo privé et Undo en mémoire (In Memory Undo), par Jonathan Lewis</title>
		<link>https://blog.developpez.com/pachot/jl_private_redo/</link>
		<comments>https://blog.developpez.com/pachot/jl_private_redo/#comments</comments>
		<pubDate>Tue, 28 Dec 2010 16:17:13 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ceci est une traduction de d&#8217;un ancien post de Jonathan Lewis sur forums.oracle.com, référencé récemment sur son blog. Il décrit le fonctionnement de la journalisation en mémoire (IMU &#8211; In Memory Undo), une optimisation introduite en 10g qui utilise des &#8230; <a href="https://blog.developpez.com/pachot/jl_private_redo/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<blockquote><p><ins>Ceci est une traduction de d&rsquo;un ancien post de Jonathan Lewis sur <a href="http://forums.oracle.com/forums/message.jspa?messageID=3974313#3974313">forums.oracle.com</a>, référencé récemment sur son <a href="http://jonathanlewis.wordpress.com/2010/12/23/private-redo/">blog</a>. Il décrit le fonctionnement de la journalisation en mémoire (IMU &#8211; In Memory Undo), une optimisation introduite en 10g qui utilise des structures en mémoire pour diminuer la contention sur les blocs d&rsquo;undo et le redo log buffer.</ins></p></blockquote>
<p>Le contenu des blocs d&rsquo;undo et des fichiers de redo log sont quasiment les même que l&rsquo;on utilise <em>in-memory undo</em> (et les <em>private redo threads</em>) ou que l&rsquo;on utilise la journalisation &lsquo;normale&rsquo;.<br />
La principale différence se trouve dans l&rsquo;ordre où sont faites les choses.<br />
Il y a aussi, avec <em>in-memory undo</em>, une diminution du nombre de <em>redo records</em> même si le nombre de <em>change vectors</em> reste le même.</p>
<p>Voici le séquencement d&rsquo;une transaction courte avec gestion normale de la journalisation.</p>
<ul>
<li>Vous modifiez un bloc de table ou d&rsquo;index. Un vecteur de changement (<em>redo change vector</em>) est généré pour cette modification.</li>
<li>En même temps, vous devez enregistrer l&rsquo;information nécessaire pour défaire (<em>rollback</em>) de cette modification. C&rsquo;est un enregistrement d&rsquo;annulation (<em>undo record</em>) qui est généré pour décrire ce qui a été altéré.</li>
<li>Mais comme cet <em>undo record</em> est stocké dans un bloc d&rsquo;undo (rollback segment), alors un vecteur de changement <em>redo change vector</em> est généré pour décrire cette modification du bloc d&rsquo;undo</li>
<li>Oracle combine ces deux <em>redo change vector</em> (vecteurs de changement du bloc de donnée et du bloc d&rsquo;undo) dans en un enregistrement de redo (<em>redo record</em>), ce qui incrémente la statistique de session &lsquo;redo entries&rsquo;.</li>
<li>Donc pour cette modification, Oracle doit acquérir de l&rsquo;espace dans le tampon journalisation <em>redo log buffer</em> avec le latch &lsquo;redo allocation&rsquo; et y copier l&rsquo;enregistrement de redo avec le latch &lsquo;redo copy&rsquo;</li>
</ul>
<p>Si l&rsquo;on insère 10 lignes, une par une, dans une table qui a 4 indexes, alors on va générer 50 <em>redo records</em> et 50 <em>undo records</em>, et faire appel 50 fois au latches de redo: 5 <em>redo record</em> par ligne (un pour la table et un pour chaque index) pour 10 lignes.</p>
<p>Lorsque la fonctionnalité de journalisation en mémoire (<em>in-memory undo</em>) est activée, et parce que dans cet exemple il s&rsquo;agit d&rsquo;une petite transaction, voici ce qu&rsquo;il se passe:</p>
<ul>
<li>A moment où on modifie la première ligne de la table, Oracle alloue dans la shared pool son propre <strong>buffer de redo privé</strong> (appelé <em>redo strand</em>) et son propre <strong>buffer de &laquo;&nbsp;undo&nbsp;&raquo;</strong>. En fait, ce buffer de &laquo;&nbsp;undo&nbsp;&raquo; contient du redo: c&rsquo;est le redo qui décrit ce qui doit être modifié dans les bloc d&rsquo;<em>undo</em>.</li>
<li>Lors de la mise à jour de la table et des index, chaque <em>change vector</em> qui décrit la modification est écrit dans le <em>buffer de redo privé</em>.</li>
<li>En même temps, les <em>change vector</em> qui décrivent le <em>undo record</em> correspondant sont écrits dans le <strong>buffer de &laquo;&nbsp;undo&nbsp;&raquo; privé</strong>.</li>
<li>Le nombre total de <em>change vectors</em>, et leur contenu sont exactement les mêmes que pour les <em>change vectors</em> traditionnels.</li>
<li>Au commit, oracle concatène ces 2 buffers pour faire <strong>un seul <em>redo record</em></strong> et l&rsquo;écrit dans le tampon de journalisation normal (<em>redo log buffer</em>)</li>
<li>En même temps, ces 100 <em>change vectors</em> sont appliqués: 10 sur la table, 10 sur chaque index, et 50 sur les blocs d&rsquo;undo. Et en dehors de cela, tout ce qui doit se faire lors d&rsquo;un commit s&rsquo;applique aussi.</li>
<li>Le nombre de modification de blocs (&laquo;&nbsp;db block changes&nbsp;&raquo;) reste le même dans tous les cas</li>
<li>La différence la plus significative dans le volume de redo généré vient de l&rsquo;entête du <em>redo record</em> qui fait 12 octets. Avec la gestion &lsquo;in-memory&rsquo; de l&rsquo;undo il n&rsquo;y  qu&rsquo;un seul <em>redo record</em>, donc un <em>header</em> de 12 octets, alors que la méthode traditionnelle en génère 50, donc 50*12=600 octets.</li>
</ul>
<p>Il y a de nombreux détails et variations autour de ce qui se passe là. Par exemple au début et à la fin de la transaction, ou lorsque un des deux buffers est plein (puisqu&rsquo;ils ne font que 64Ko ou 128Ko) mais la description faite ci-dessus couvre les différences essentielles.</p>
<blockquote><p><ins>Question:</ins> Supposons que je démarre l&rsquo;instance et effectue quelques mises à jour. J&rsquo;ai donc un buffer privé de redo et un buffer privé de undo, créés en shared pool. Immédiatement après le système se plante et rien n&rsquo;est encore écrit dans les fichiers de redo ni dans les blocs d&rsquo;undo. Dans cette situation comment fait Oracle pour récupérer les données d&rsquo;undo ?</p></blockquote>
<p>Il y a deux chose que vous devez prendre en compte dans ma description:</p>
<ul>
<li>la précision: &lsquo;Il y a de nombreux détails et variations&rsquo;</li>
<li>la partie qui montre que les modifications faites dans les blocs tables et index est tout à la fin.</li>
</ul>
<p>Si la session a fait un commit, elle a écrit le redo privé dans le <em>redo thread</em> public, qui doit être écrit sur disque avant que le commit ne soit terminé. Donc il n&rsquo;y a rien de différent au niveau du recovery.</p>
<p>Maintenant, si la session n&rsquo;a pas encore fait de commit, alors du point de vue des autres utilisateurs, rien ne s&rsquo;est encore passé (ils ne sont censés voir que les effets des transactions commitées). Du coup, cela n&rsquo;a pas d&rsquo;importance que les redo et undo privés aient disparu.</p>
<p>Mais voici où ca devient plus complexe: Comment les autres sessions voient que vous êtes en train de modifier les mêmes blocs qu&rsquo;elles, si vous ne les mettez à jour que lorsque vous faites le commit de votre transaction ? Comment Oracle fait pour minimiser le temps que prennent toutes les modifications de blocs qui doivent être faites lors du commit ? J&rsquo;ai quelques réponses à ces questions, mais elles ne sont ni exactes, ni complètes, alors je ne préfère pas les publier.</p>
<p>Cependant, un point clé de ce mécanisme, c&rsquo;est le fait qu&rsquo;il ne s&rsquo;applique qu&rsquo;à des petites transactions. Les zones privées ne font que 64Ko ou 128Ko suivant qu&rsquo;on est en 32 ou 64 bits, et dès que la transaction devient trop grande, Oracle les écrit dans les <em>redo buffer</em> et poursuit avec le mécanisme normal. </p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Fragmentation &#8211; Index, par Jonathan Lewis (4ème partie)</title>
		<link>https://blog.developpez.com/pachot/jl_fragmentation_4/</link>
		<comments>https://blog.developpez.com/pachot/jl_fragmentation_4/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 19:57:00 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>
		<category><![CDATA[Traductions]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ceci est une traduction de d&#8217;un post de Jonathan Lewis sur son blog &#8211; la quatrième et dernière partie d&#8217;une série de quatre sur la fragmentation (original en anglais). Il est conseillé de lire avant: Fragmentation &#8211; Introduction, Fragmentation &#8211; &#8230; <a href="https://blog.developpez.com/pachot/jl_fragmentation_4/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<blockquote><p><ins>Ceci est une traduction de d&rsquo;un post de Jonathan Lewis sur son blog &#8211; la quatrième et dernière partie d&rsquo;une série de quatre sur la fragmentation (<a href="http://jonathanlewis.wordpress.com/2010/07/22/fragmentation-4/">original en anglais</a>). Il est conseillé de lire avant: <a href="http://blog.developpez.com/pachot/p9125/auteurs/jl-fragmentation-1/">Fragmentation &#8211; Introduction</a>, <a href="http://blog.developpez.com/pachot/p9126/auteurs/jl-fragmentation-2/">Fragmentation &#8211; Disque et Tablespace</a>, <a href="http://blog.developpez.com/pachot/p9193/auteurs/jl-fragmentation-3/">Fragmentation &#8211; Table</a></ins></p></blockquote>
<h2>Fragmentation Index</h2>
<p>La fragmentation en extents multiples et la fragmentation due à ASSM que j&rsquo;ai décrit dans la note précédente à propos des tables s&rsquo;appliquent aussi aux indexes, bien sûr, et nous importe de la même manière, c&rsquo;est à dire presque jamais. Lorsque les gens parlent de fragmentation d&rsquo;index, ils pensent en général au problème des blocs avec un faible taux de remplissage (<em>sparsely populated blocks</em>) qui est aussi un phénomène que j&rsquo;ai décrit à propos de la fragmentation des tables, mais il y a quelques différences entre une table et un index, que nous allons examiner tout de suite.<br />
Il est intéressant de considérer aussi un autre sens possible pour la fragmentation d&rsquo;un index, que nous allons aussi examiner: c&rsquo;est l&rsquo;effet de bord de la division d&rsquo;un bloc feuille (<em>leaf block splitting</em>) qui fait que des blocs qui sont logiquement à la suite se retrouvent physiquement dispersés.<br />
<span id="more-7"></span><br />
Nous allons commencer avec une suppression en masse, et étudier les mêmes cas représentatif que nous avons vu à propos des tables (c&rsquo;est à dire 20% des blocs ayant 100% de leurs ligne supprimées, et 100% des blocs ayant 20% de leur lignes supprimées). Et quand on fait ça, il faut garder à l&rsquo;esprit que la suppression dans un index est différente de la suppression dans une table, d&rsquo;où une différence de comportement dans ce qui suit.<br />
Lorsqu&rsquo;une transaction supprime une ligne d&rsquo;une table (DELETE) la ligne est réduite à un <em>stub</em> de quelques octets, avant que ne se fasse le <strong>commit</strong>, et elle peut réutiliser immédiatement l&rsquo;espace libéré dans le bloc de la table. Mais lorsqu&rsquo;une transaction supprime une ligne d&rsquo;un index, il doit laisser en place l&rsquo;entrée d&rsquo;index entière, et la marquer comme supprimée. Elle ne peut pas réutiliser l&rsquo;espace immédiatement, mais cela doit attendre que le <strong>commit</strong> soit fait.</p>
<p>Une autre différence majeure entre une table et un index est le fait que dans un index chaque entrée a sa place et doit aller au bon endroit. Ce qui fait que lorsqu&rsquo;un bloc d&rsquo;index a de l&rsquo;espace libre, sans être complètement vide, il n&rsquo;y a que les lignes qui correspondent exactement à cette partie de l&rsquo;index (<ins>à cette plage de valeurs</ins>) qui peuvent réutiliser cet espace.  </p>
<p>De plus, lorsqu&rsquo;un bloc feuille devient complètement vide, il reste toujours chaîné dans la même position de la structure de l&rsquo;index, même s&rsquo;il est aussi référencé par la <em>freelist</em>. (Mon hypothèse là dessus est qu&rsquo;il est probablement plus facile de gérer les problèmes de lecture cohérente &#8211; <em>read consistency</em> &#8211; mais cela peut aussi être lié à des problèmes de rollback et au coût de la modification de 3 pointeurs dans la structure de l&rsquo;index.) Ce qui veut dire que si on a un index qui a eu une large suppression des valeurs les plus basses, alors une requête qui demande la valeur minimum va devoir faire un range scan d&rsquo;un grand nombre de blocs vides avant de trouver le bloc feuille qui contient une donnée présente. C&rsquo;est pour cela qu&rsquo;il faut toujours penser à faire un ALTER INDEX &#8230; COALESCE sur un index lorsqu&rsquo;on supprime fréquemment les premières entrées. Et de manière plus générique, même si c&rsquo;est moins courant, lorsque on un supprime un grand nombre de valeurs consécutives n&rsquo;importe où dans l&rsquo;index.</p>
<p>Dans le cas plus général d&rsquo;un suppression en masse, on peut se retrouver avec un espace libre important dans tous les blocs feuilles et, contrairement à l&rsquo;espace libre des tables, on ne peut pas faire en sorte qu&rsquo;Oracle le réutilise en choisissant une valeur idéale pour PCTUSED puisque ce paramètre n&rsquo;a pas de sens pour un index. Donc, dans le cas des index, la question que l&rsquo;on doit se poser est: à quel point cet espace libre a un impact sur l&rsquo;application.</p>
<p>Les considérations habituelles s&rsquo;appliquent ici, bien sûr:  un plus gros volume à sauvegarder lors des <em>backup </em>et plus de blocs à garder en <em>buffer cache</em>. Mais nous devons voir si le fait d&rsquo;avoir un grand nombre de blocs feuilles faiblement remplis n&rsquo;a pas un impact plus direct et plus significatif sur les performances.<br />
La réponse est dépendante de l&rsquo;application, bien sûr. Mais en général un index est utilisé pour lister les valeurs clés et les regrouper dans un faible espace. Et en gardant cela à l&rsquo;esprit, on peut voir que le plus gros du travail de la plupart des requêtes est passé à aller voir les lignes de la table après avoir récupéré un certain nombre de valeurs clés dans l&rsquo;index. Par conséquent, le travail supplémentaire venant du fait qu&rsquo;il y a une grand quantité d&rsquo;espace libre dans les blocs feuilles de l&rsquo;index n&rsquo;est qu&rsquo;une petite fraction du travail total de la requête. Et on peut donc décider de ne pas dépenser des ressources à réorganiser les index sauf s&rsquo;ils sont vraiment très faiblement remplis. (Un index B-Arbre typique avec une arrivée aléatoire va tourner avec un taux d&rsquo;utilisation de 70%, donc 30% d&rsquo;espace libre, dans les blocs feuilles. Je ne suis pas particulièrement inquiet des performances d&rsquo;un index avant que le taux d&rsquo;utilisation ne passe en dessous de 50%, sauf si j&rsquo;ai une preuve que cet index contribue significativement au temps d&rsquo;exécution d&rsquo;un ensemble de requêtes critiques.)</p>
<p>Il y a cependant deux autres problèmes de &lsquo;fragmentation&rsquo; spécifiques aux index, et qui n&rsquo;existent pas avec les tables. </p>
<p>Le premier est le fait qu&rsquo;on ne met pas à jour une entrée d&rsquo;index: on supprime l&rsquo;entrée correspondant à l&rsquo;ancienne valeur, et on ajoute la nouvelle entrée correspondant à la nouvelle valeur. Si ces mises à jours se font de manière aléatoire, alors il n&rsquo;y a aucun des problèmes associés aux suppressions de masse. Mais si il y a un pattern de modification lié au temps, par exemple si vous avez un index sur une colonne &lsquo;dernière_modification&rsquo; alors vous pouvez vous retrouver avec le pire effet d&rsquo;un index partiellement rempli. Dans un cas comme celui-ci, vous allez supprimer (lentement) des entrées vers le début de l&rsquo;index pour les insérer tout à la fin. Et l&rsquo;espace libéré par les suppression ne sera jamais réutilisé puisque les lignes ne peuvent pas êtres modifiées dans le passé. En plus, si vous continuez à modifier des lignes du passé vers le futur, vous continuez à visiter des blocs faiblement remplis. Et si c&rsquo;est un système transactionnel où les utilisateurs modifient une ou deux lignes à chaque fois, la recherche de l&rsquo;entrée et la mise à jour dans l&rsquo;index peut prendre une proportion significative du travail effectué par chaque requête d&rsquo;update. Vous devez au moins être au courant de ce type d&rsquo;activité afin de prévoir comment en mesurer l&rsquo;impact sur les performances et adopter une stratégie pour y faire face.</p>
<p>Le deuxième type de fragmentation propre aux index, pour lequel le terme de fragmentation semble le plus approprié, vient des divisions des blocs feuilles (<em>leaf block split</em>). Si vous voulez ajouter une entrée dans un bloc feuille qui est plein, alors Oracle doit trouver un bloc vide quelque part, y déplacer à peu près la moitié des données du bloc courant, puis lier ce bloc à sa bonne place dans la structure de l&rsquo;index. Par consequent, les blocs qui sont &lsquo;logiquement&rsquo; adjacents ne sont pas nécessairement &lsquo;physiquement&rsquo; adjacents. Cela veut dire que lorsque vous faites un <em>index range scan</em> assez large (ou un <em>index full scan</em>) vous vous retrouvez à faire beaucoup de lectures aléatoires de blocs.</p>
<p>C&rsquo;est ici que SQL Server (et probablement sybase et peut-être DB2) entrent en jeu. La manière dont SQL Server gère l&rsquo;espace libre pour les tables non clusterisées (<em>heap tables</em>) n&rsquo;est pas très efficace. Donc c&rsquo;est presque un article de foi (voire un dogme) que toutes les tables dans SQL Server doivent être construites en index cluster (<em>clustered indexes</em>), ce qui veut dire dans les termes Oracle, que toutes les tables sont des IOT (<em>index organized tables</em> tables organisées en index).  Si vous avez essayé de regrouper (<em>cluster</em>) vos données, et y avez réfléchi soigneusement et délibérément, alors les divisions des blocs feuilles (<em>leaf block split</em>) détruisent votre effort de garder ensemble les données liées. Il n&rsquo;est donc pas surprenant que les DBA qui ont une expérience en SQL Server (et Sybase et DB2) soient si favorables à l&rsquo;idée de reconstruire les index fréquemment. Si vous reconstruisez un index cluster, vous ramenez les enregistrements là où vous voulez. Heureusement, cela ne nécessite pas de reconstruire tous les autres indexes de la table puisque, comme les index secondaires des IOT d&rsquo;Oracle, les autres indexes en SQL Server utilisent la clé unique (ou rendue unique) comme identifiant de la ligne.</p>
<p>Pour Oracle, ce type de fragmentation ne pose généralement pas de problème, à condition qu&rsquo;il concerne des index B-arbre standard, vu que, comme c&rsquo;est précisé plus haut, la plupart des requêtes passent la plus grande partie de leur temps à visiter la table. Mais le cas de SQL Server donne une indication du cas où vous devrez considérer plus sérieusement les effets de la &lsquo;fragmentation&rsquo; et le besoin de reconstruire les index. Si, en tant que DBA Oracle vous avez crée une table en IOT, alors vous aviez probablement une bonne raison de faire ce choix, et il s&rsquo;agissait probablement de s&rsquo;assurer que les données qui arrivent dans un certain ordre sont stockées dans un autre ordre, afin de garder ensemble des données qui sont liées.</p>
<p>Si vous avez crée une IOT pour garder les données regroupées, alors les divisions de blocs feuilles vont amener les données à être un peu dispersées. Avant de s&rsquo;inquiéter, il faut étudier l&rsquo;importance de cette dispersion, et le bénéfice, peut-être marginal, d&rsquo;y faire quelque chose. Pour illustrer cela, imaginez que vous ayez une requête sur une table IOT importante qui récupère 200 lignes de 200 octets. Comme sur une table normale cela aurait demandé à lire 200 blocs différents dispersés aléatoirement, vous avez décidé d&rsquo;implémenter la table en IOT. Si l&rsquo;on prends le cas le pire pour le divisions de blocs feuilles (50/50 avec aucun re-remplissage) alors les 200 lignes vont aller dans la IOT avec environ 20 lignes par blocs sur un total de 10 blocs feuilles. A cause du moment où chaque division de bloc feuille a lieu, on peut penser que ces 1à blocs vont finir dispersés assez aléatoirement dans tout le segment d&rsquo;index. Si vous reconstruisez l&rsquo;index, vous allez pouvoir compacter les données sur seulement 5 blocs, et ces 5 blocs vont souvent être adjacents dans le segment plutôt que dispersés. Et ce regroupement ca probablement faire que vous aurez un petit bénéfice de performance si l&rsquo;<em>index range scan</em> doit aller sur disque. Note: SQL Server travaille avec des tailles d&rsquo;extents de 8 blocs de 8 KB et le logiciel de base de donnée peut coopérer avec le système d&rsquo;exploitation pour négocier une lecture en avance (<em>readahead</em>) de l&rsquo;extent complet dans ce genre de situation. Cet ensemble de détails font que la réorganisation d&rsquo;index dans ces circonstances et plus bénéfique sur SQL Server que ce cerait le cas sur Oracle.</p>
<p>Après avoir passé un peu de temps à réfléchir à ce genre de scénario, il est plus facile de comprendre comment évaluer le bénéfice que vous pouvez tirer de la réorganisation d&rsquo;une IOT. Quelle est la rédution du nombre total de visites de blocs que vous aurez à faire ? Combien de ces visites seraient des I/O disque distincts ? Quel serait le bénéfice du point de vue d&rsquo;Oracle, du système d&rsquo;exploitation, des drivers hardware, capable d&rsquo;implémenter un <em>readahead</em> qui réduit le temps de lecture de ces blocs ? Gardez à l&rsquo;esprit la remarque importante que j&rsquo;ai fait dans l&rsquo;article sur la fragmentation de disque: même si deux blocs aparaissent comme adjacent du point de vue des fichiers Oracle, l&rsquo;introduction du <em>stripping</em>, et du <em>load balancing</em> peuvent faire que ces deux blocs sont sur des disques différents.</p>
<p><ins>Fin de la série</ins></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fragmentation &#8211; Table, par Jonathan Lewis (3ème partie)</title>
		<link>https://blog.developpez.com/pachot/jl_fragmentation_3/</link>
		<comments>https://blog.developpez.com/pachot/jl_fragmentation_3/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 19:55:00 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>
		<category><![CDATA[Traductions]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ceci est une traduction de d&#8217;un post de Jonathan Lewis sur son blog &#8211; la troisième partie d&#8217;une série de quatre sur la fragmentation (original en anglais). Il est conseillé de lire avant: Fragmentation &#8211; Introduction, Fragmentation &#8211; Disque et &#8230; <a href="https://blog.developpez.com/pachot/jl_fragmentation_3/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<blockquote><p><ins>Ceci est une traduction de d&rsquo;un post de Jonathan Lewis sur son blog &#8211; la troisième partie d&rsquo;une série de quatre sur la fragmentation (<a href="http://jonathanlewis.wordpress.com/2010/07/19/fragmentation-3/">original en anglais</a>). Il est conseillé de lire avant: <a href="http://blog.developpez.com/pachot/p9125/auteurs/jl-fragmentation-1/">Fragmentation &#8211; Introduction</a>, <a href="http://blog.developpez.com/pachot/p9126/auteurs/jl-fragmentation-2/">Fragmentation &#8211; Disque et Tablespace</a></ins></p></blockquote>
<h2> Fragmentation Table</h2>
<p>Dans l&rsquo;<a href="http://blog.developpez.com/pachot/p9125/auteurs/jl-fragmentation-1/">introduction</a> nous avons parlé d&rsquo;un type de fragmentation au niveau table qui, en général, ne pose pas de problème: la fragmentation d&rsquo;une table en plusieurs <em>extents</em>. Et il y a une chose amusante, c&rsquo;est que ASSM (<em>Automatic Segment Space Management</em> &#8211; la gestion automatique de l&rsquo;espace libre dans les segments) a introduit une nouvelle forme de fragmentation, mais qui ne pose généralement pas de problème non plus.<br />
<span id="more-6"></span></p>
<p>En ASSM, lorsqu&rsquo;un processus Oracle vérifie le <em>bitmap</em> qui garde la trace de l&rsquo;espace libre d&rsquo;un objet, et qu&rsquo;il ne trouve pas assez d&rsquo;espace libre pour insérer de nouvelles données, alors il va formater 16 blocs <u>quelque part</u> dans l&rsquo;<em>extent</em> en cours (après avoir alloué un nouvel <em>extent</em> si nécessaire). Ces 16 blocs peuvent être n&rsquo;importe où dans l&rsquo;<em>extent</em> (du moment que le numéro du bloc de départ par rapport à l&rsquo;<em>extent</em> soit un multiple de 16).<br />
L&rsquo;emplacement de cet ensemble de 16 blocs est déterminé par l&rsquo;identifiant du processus (le PID &#8211; <em>process id</em>), de même que le choix du bloc à utiliser parmi ces 16. Ce qui veut dire si vous créez une table dans un tablespace qui a des extents uniformes de 1Mo, vous pouvez vous  retrouver à ce que la première ligne que vous insérez se retrouve dans le tout dernier bloc de son extent.<br />
Cela n&rsquo;a généralement pas d&rsquo;importance parce que:</p>
<ul>
<li>la plupart des accès I/O se font bloc par bloc plutot que par full scan, et donc l&rsquo;emplacement du bloc dans l&rsquo;extent n&rsquo;a pas beaucoup d&rsquo;importance.</li>
<li>ce &lsquo;désordre&rsquo; ne se retrouve en principe que sur le dernier extent de la table</li>
<li>en cas de full scan, pour savoir quel morceaux de 16 blocs doivent être traités de manière spéciale, Oracle utilise un mécanisme qui minimise le surcoût de cette vérification, en utilisant les LHWM (<em>low high water mark</em>) and HHWM (<em>high high water mark</em>).  </li>
</ul>
<p>Le type de fragmentation de table le plus important, et le plus courant, vient des données qui sont supprimées, et on peut alors se préoccuper des blocs qui ont un faible taux de remplissage. Lorsqu&rsquo;on crée une table, on précise l&rsquo;espace qui doit être réservé dans chaque bloc afin de garder une marge pour les lignes qui vont être modifiées (UPDATE) et &#8211; explicitement en <em>freelist </em>ou implicitement en ASSM &#8211; on précise aussi l&rsquo;espace libre que doit contenir un bloc pour qu&rsquo;il puisse être à nouveau la cible d&rsquo;une nouvelle insertion de données (INSERT).  </p>
<p>Si on regarde tous les scénarios possibles qui doivent être pris en compte avec avec des insertions de données, des modifications et des suppressions, on se rend compte à quel point il peut être difficile pour Oracle d&rsquo;écrire du code qui gère l&rsquo;espace libre de façon efficace et opportune. On voit aussi à quel point il est difficile, en tant que développeur ou DBA, de préciser des limites raisonnables pour la gestion de l&rsquo;espace afin de minimiser les problèmes de performances dans des cas extrêmes. Au final, il est possible de se retrouver avec une table  qui a une quantité importante d&rsquo;espace libre dans chaque bloc, et il faut alors se poser les questions suivantes: Comment ce espace libre est arrivé là ? Est-ce qu&rsquo;il pose un problème de performance ? Est-ce que vous allez pouvoir le réutiliser ? Est-ce que vous allez pouvoir le réutiliser en temps opportun ? Si vous arrivez à le réutiliser, est-ce que ca n&rsquo;introduit pas un autre type de problème de performance ?</p>
<p>Prenez le cas où vous purgez la première année de données après que votre système ait tourné pendant 5 ans. Cela va probalement faire que les 20% premiers blocs de la table seront complètement vides. Il iront en <em>freelist</em>. Ou en ASSM, à l&rsquo;exception de quelques bugs, ils seront marqués comme ayant de l&rsquo;espace libre. Et cet espace libre pourra donc être réutilisé plus tard. De plus, si les performances de votre application dépendent du fait que les données qui arrivent au même moment se retrouvent ensembles (<em>clustering</em> par rapport à la date/heure d&rsquo;arrivée) alors de la manière dont l&rsquo;espace libre est rempli, le <em>clustering</em> va normalement rester intact. <br />
Par une bizarrerie de l&rsquo;implémentation, les blocs vont être utilisés dans l&rsquo;ordre inverse en gestion <em>freelist </em>et dans l&rsquo;ordre normal en ASSM (et une question me traverse l&rsquo;esprit à ce moment à propos de l&rsquo;impact de cet ordre inverse sur les indexes non-uniques qui ont peu de valeurs distinctes).</p>
<p>Cependant, pour un bon moment, avant cette réutilisation, les <em>full scan</em> de la table vont prendre 20% de temps en plus de ce qui est nécessaire. Et vous pouvez vous retrouver à faire un <em>backup </em>d&rsquo;un fichier plus gros que ce dont vous avez réellement besoin. Ces considérations peuvent alors vous décider à faire une réorganisation de la table (et d&rsquo;un <em>rebuild </em>des index) en la déplaçant vers un autre tablespace. Et elles peuvent aussi vous amener a réfléchir au partitionnement de la table.</p>
<p>Imaginez le cas d&rsquo;un système de vente par internet où les utilisateurs remplissent leur panier, paniers qui à la fin deviennent une commande. Inévitablement, certains utilisateurs vont remplir un panier sans passer la commande par la suite. Alors vous avez peut-être un programme en tâche de fond qui regarde les vieux paniers et le supprime de la base. Il y a deux imperfections dans cette implémentation, mais ce genre d&rsquo;erreur se voit souvent sur des systèmes en production. Alors dans ce cas, vous vous retrouvez avec une table qui subit constamment des <em>delete</em> sur le passé récent, de telle sorte que si vous analysez la table, vous verrez qu&rsquo;en moyenne elle a, disons, 20% d&rsquo;espace libre dans chaque bloc, à l&rsquo;exception des quelques blocs qui contiennent les paniers récents. </p>
<p>Si vous êtes en ASSM, ces 20% ne seront jamais réutilisés (sauf si en recréant la table) parce que la granularité de ASSM fait qu&rsquo;il faut au moins 25% d&rsquo;espace libre dans un bloc avant que son statut ne passe de <em>&lsquo;plein&rsquo;</em> à <em>&lsquo;0% – 25% libre&rsquo;</em>. Mais si vous êtes en <em>freelist</em> alors vous avez peut-être prévu le coup en mettant PCTUSED à un peu plus que 80. Dans ce cas, les blocs reviennent en <em>freelist</em> dès que l&rsquo;espace libre atteint 20%, et l&rsquo;espace va être réutilisé. <br />
Cela semble être une bonne idée, sauf qu&rsquo;il y a un autre problème à prendre en considération.</p>
<p>Peut-être que les bonnes performances de votre application venaient du fait que les paniers des derniers jours sont stockés dans les N derniers blocs de la table. Du fait que vous libérez 20% de l&rsquo;espace des blocs du passé, alors les paniers qui étaient stockés sur N blocs sont maintenant répartis sur 5 fois plus de blocs. Et cela veut dire que, si vous voulez garder le même niveau de performance, vous allez avoir besoin de plus de mémoire en <em>buffer cache</em>.</p>
<p>La conclusion générale est la suivante. Une fois que vous avez résolu une fois pour toutes le problème de la taille des <em>extents </em> d&rsquo;une table, le seul problème de &lsquo;fragmentation&rsquo; qui vous reste à prendre en compte est celui des blocs qui ne sont que partiellement remplis. Et il y a des patterns de suppression de données qui peuvent amener à cette situation de blocs sous-utilisés. Dans certains cas, il n&rsquo;est possible de récupérer cet espace que par une réorganisation de la table (et dans tous les cas, c&rsquo;est le partitionnement de la table qui peut faire que cette option est viable). Mais il y a aussi des patterns de suppression de données qui font que l&rsquo;espace libre est réutilisable, mais que vous ne voulez pas toujours réutiliser cet espace, car cela peut amener un autre type de problème.</p>
<p><ins>La suite: <a href="http://blog.developpez.com/pachot/p9194/auteurs/jl-fragmentation-4/">Fragmentation &#8211; Index</a></ins></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fragmentation &#8211; Introduction, par Jonathan Lewis</title>
		<link>https://blog.developpez.com/pachot/jl_fragmentation_1/</link>
		<comments>https://blog.developpez.com/pachot/jl_fragmentation_1/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 19:53:00 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>
		<category><![CDATA[Traductions]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ceci est une traduction d&#8217;un post de Jonathan Lewis sur son blog &#8211; la première partie d&#8217;une série de quatre sur la fragmentation (original en anglais) Cet article a commencé comme une note brève, jusqu&#8217;à ce que je réalise que &#8230; <a href="https://blog.developpez.com/pachot/jl_fragmentation_1/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<blockquote><p><ins>Ceci est une traduction d&rsquo;un post de Jonathan Lewis sur son blog &#8211; la première partie d&rsquo;une série de quatre sur la fragmentation (<a href="http://jonathanlewis.wordpress.com/2010/07/13/fragmentation-1/">original en anglais</a>)</ins></p></blockquote>
<p>Cet article a commencé comme une note brève, jusqu&rsquo;à ce que je réalise que ça allait être plus important, et que j&rsquo;en fasse plutôt une série de quatre articles:</p>
<ul>
<li><a href="http://blog.developpez.com/pachot/p9125/auteurs/jl-fragmentation-1/">Fragmentation &#8211; Introduction</a></li>
<li><a href="http://blog.developpez.com/pachot/p9126/auteurs/jl-fragmentation-2/">Fragmentation &#8211; Disque et Tablespace</a></li>
<li><a href="http://blog.developpez.com/pachot/p9193/auteurs/jl-fragmentation-3/">Fragmentation &#8211; Table</a> <ins></ins></li>
<li><a href="http://blog.developpez.com/pachot/p9194/auteurs/jl-fragmentation-4/">Fragmentation &#8211; Index</a> <ins></ins></li>
</ul>
<h2>Introduction</h2>
<p>Le mot &lsquo;<strong>fragmentation</strong>&lsquo; donne l&rsquo;idée de quelque chose qui est cassé en plusieurs morceaux, mais il a aussi une connotation émotionnelle qui fait penser qu&rsquo;il y a beaucoup de petits morceaux. Dans le contexte d&rsquo;une base Oracle, vous devez savoir ce que vous entendez par &lsquo;morceau&rsquo;, ainsi que la granularité de ces morceaux, et leur impact possible sur les performances.<br />
<span id="more-4"></span><br />
Vu qu&rsquo;il est possible de parler de fragmentation au niveau disque (disque logique), ou au niveau fichier, niveau tablespace, niveau segment, niveau extent ou niveau block, il est important de savoir très clairement ce que vous essayez de dire lorsque vous faites un commentaire du genre &lsquo;Mon tablespace est fragmenté&rsquo; ou &lsquo;Mon index est fragmenté&rsquo;</p>
<p>Partons sur un exemple: Je crée un nouveau tablespace et je déplace une table dedans (ALTER TABLE &#8230; MOVE).<br />
Lorsque je regarde <strong>DBA_EXTENTS</strong>, ma table a 100 extents. Il est évident qu&rsquo;il y a &lsquo;fragmentation&rsquo; dans le sens premier de ce mot, puisque j&rsquo;ai 100 différents morceaux. Mais d&rsquo;autre part, puisque cette table est la première chose que j&rsquo;ai créé dans ce tablespace, je vois que ces extents sont adjacents. On pourrait alors dire que la table est &lsquo;<strong>logiquement fragmentée</strong>&lsquo; mais &lsquo;<strong>physiquement contiguë </strong>&lsquo;.</p>
<p>Est-ce que ce type de fragmentation a un impact sur les performances du système ? </p>
<p>Vu qu&rsquo;Oracle fait la plupart des I/O par bloc (nous lisons des blocs vers le buffer cache, nous écrivons des blocs dans les fichiers), et vu qu&rsquo;il n&rsquo;y a pas de conséquences au fait qu&rsquo;un bloc appartienne à <em>extent </em>plutôt qu&rsquo;un autre, alors la réponse est probablement: non.<br />
Cependant, il y a des fois où on essaie de lire plusieurs blocs contigus en un seul I/O (<em>full table</em> scan et <em>index fast full scan</em>), alors y a-t-il des conséquences au fait que notre table &lsquo;physiquement contiguë&rsquo; soit &lsquo;logiquement fragmentée&rsquo; en un grand nombre d&rsquo;extents ?</p>
<p>Que se passe-t-il si les extents font, disons, 64Ko chacun. Est-ce que cela limite la taille d&rsquo;une lecture multi-bloc (<em>db file multiblock read</em>) ? Ou bien ces lectures peuvent-elles être à cheval sur deux extents ? Et si le tablespace a deux datafiles ou plus, dans ce cas l&rsquo;allocation des extents se fait généralement en alternant les datafiles (<em>round-robin</em>), est-ce que cela affecte la manière dont les lectures pourront se faire ? Et si on fait des <em>full table scan</em> en <em>parallel query</em> (<em>parallel tablescan</em>), est-ce qu&rsquo;il y a des restrictions différentes pour les lectures directes (<em>direct-path reads</em>) ? </p>
<p>Si vous faites tourner un <em>datawarehouse </em>qui passe beaucoup de son temps à faire ce type d&rsquo;opérations, alors ce sont quelques unes des questions auquelles vous devrez savoir répondre. Voir, par exemple, une <a href="http://jonathanlewis.wordpress.com/2007/05/29/autoallocate-and-px/">note</a> que j&rsquo;ai écrit il y a trois ans à propos d&rsquo;anomalies dans les tailles d&rsquo;I/O lorsqu&rsquo;on est en <em>parallel query</em>, et l&rsquo;amélioration faite là dessus en 11G qui a été décrite <a href="http://go2.wordpress.com/?id=725X1342&amp;site=jonathanlewis.wordpress.com&amp;url=http%3A%2F%2Fantognini.ch%2F2009%2F08%2Fsystem-managed-extent-size-11g-improvements%2F&amp;sref=http%3A%2F%2Fjonathanlewis.wordpress.com%2F2010%2F07%2F13%2Ffragmentation-1%2F">ici</a> par Christian Antognini il y a quelques années.</p>
<p>Vous ne pouvez commencer à comprendre les problèmes posés par la fragmentation, et si elle a un impact <strong>- ou non -</strong> sur les performances, que lorsque vous aurez commencé à définir de manière claire ce que vous entendez par &lsquo;fragmentation&rsquo;. Dans la deuxième partie, je vais faire quelques commentaires sur la manière de réfléchir à la fragmentation au niveau disque et au niveau tablespace.</p>
<p><ins>La suite: <a href="http://blog.developpez.com/pachot/p9126/auteurs/jl-fragmentation-2/">Fragmentation &#8211; Disque et Tablespace</a></ins></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fragmentation &#8211; Disque et Tablespace, par Jonathan Lewis (2ème partie)</title>
		<link>https://blog.developpez.com/pachot/jl_fragmentation_2/</link>
		<comments>https://blog.developpez.com/pachot/jl_fragmentation_2/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 19:54:00 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>
		<category><![CDATA[Traductions]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Ceci est une traduction de d&#8217;un post de Jonathan Lewis sur son blog &#8211; la deuxième partie d&#8217;une série de quatre sur la fragmentation (original en anglais). Il est conseillé de lire avant: Fragmentation &#8211; Introduction Fragmentation Disque Les tablespaces &#8230; <a href="https://blog.developpez.com/pachot/jl_fragmentation_2/">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<blockquote><p><ins>Ceci est une traduction de d&rsquo;un post de Jonathan Lewis sur son blog &#8211; la deuxième partie d&rsquo;une série de quatre sur la fragmentation (<a href="http://jonathanlewis.wordpress.com/2010/07/16/fragmentation-2/">original en anglais</a>). Il est conseillé de lire avant: <a href="http://blog.developpez.com/pachot/p9125/auteurs/jl-fragmentation-1/">Fragmentation &#8211; Introduction</a></ins></p></blockquote>
<h2>Fragmentation Disque</h2>
<p>Les tablespaces sont composés de fichiers, et les fichiers sont stockés sur disque. Il s&rsquo;agit la plupart du temps de disques logiques (<em>logical volumes</em>) plutôt que de vrais disques directement (<em>real devices</em>).<br />
Lorsqu&rsquo;on fait une lecture sur un vrai disque, la taille des données qu&rsquo;on peut lire en une seule opération physique est quelque chose comme 400Ko ou 500Ko. C&rsquo;est le contenu d&rsquo;une seule piste sur un seul plateau d&rsquo;un disque physique. Une lecture plus large continue en passant sur un autre plateau (ce n&rsquo;est pas un mouvement physique des têtes, mais une commutation &lsquo;électronique&rsquo;) , ou bien en passant sur une autre piste (c&rsquo;est alors un mouvement physique, mouvement latéral de la tête), ou encore en passant sur un autre disque. Passer sur un autre disque, c&rsquo;est rejoindre une autre file d&rsquo;attente de disque, et dans ce cas le logiciel du SAN, ou l&rsquo;équivalent, aura probablement anticipé les disques dont vous aurez besoin et aura lancé en parallèle ces demandes de lectures dans les files d&rsquo;attentes correspondantes.<br />
<span id="more-5"></span><br />
Lorsque vous créez un datafile sous Oracle, vous ne savez pas à quel point le fichier est dispersé sur les disques physiques du système. <strong>Au mieux</strong>, une lecture de 1Mo va impliquer 3 ou 4 rotations d&rsquo;un même disque, avec seulement des passage d&rsquo;un plateau à l&rsquo;autre (commutations &lsquo;électroniques&rsquo;). <strong>Et au pire</strong>, j&rsquo;ai déjà vu un seul I/O impliquer jusqu&rsquo;à 32 opérations différentes sur les disques, à cause des nombreuses couches de logicielles utilisés pour stripper sur les disques, puis sur les groupes de disques (<em>diskgroup</em>), puis sur les volumes logiques (<em>logical volumes</em>), etc.<br />
Si on est tout seul sur le SAN, ce dernier cas où la lecture est parallélisée sur tous les disques est vraiment optimal pour les performances. Mais sur un système en production, c&rsquo;est une calamité pour les files d&rsquo;attentes. C&rsquo;est pour cette raison que c&rsquo;est une bonne stratégie de présenter des disques &lsquo;bruts&rsquo; à ASM, en ayant une seule couche logicielle entre Oracle et les disques, et il s&rsquo;agit en plus d&rsquo;une couche logicielle qui connaît le comportement et les données d&rsquo;Oracle.</p>
<p>A retenir: Ne pas mettre trop de couches de logiciels &lsquo;intelligents&rsquo; entre Oracle et les lecteurs de disque.</p>
<h2>Fragmentation Tablespace</h2>
<p>Bien sûr, vous pouvez créer un tablespace avec plusieurs fichiers. Alors, par définition, le tablespace est fragmenté, même si il n&rsquo;y a à la base rien de négatif avec ce type de fragmentation. Mais comme je l&rsquo;ai précisé dans la note précédente (<a href="http://blog.developpez.com/pachot/p9125/auteurs/jl-fragmentation-1/">introduction</a>), cela peut avoir des effets de bord sur la disposition des extents d&rsquo;un segment, et arriver à des cas où vous voulez faire une seule lecture d&rsquo;un gros volume de données, et vous retrouver en fait à faire plusieurs I/O plus petits &#8211; avec pour conséquence une augmentation de l&rsquo;attente sur les I/O.</p>
<p>Le cas de fragmentation que la plupart des gens ont à l&rsquo;esprit quand ils parlent de fragmentation de tablespace, c&rsquo;est à dire le fait qu&rsquo;il y ait des &lsquo;trous&rsquo; d&rsquo;espace libre au milieu de l&rsquo;espace alloué, est quelque chose qui a aussi été appelé &lsquo;gruyèrisation&rsquo; (ou en anglais <em>honey-combing</em> ou <em>bubbling</em>). C&rsquo;est un effet de bord lorsqu&rsquo;on supprime (<em>DROP</em>) ou réduit (<em>SHRINK</em>) des objects, qu&rsquo;on déplace des tables (<em>MOVE</em>) ou qu&rsquo;on reconstruit des indexes (<em>REBUILD</em>). On finit par avoir des morceaux d&rsquo;espace libre dispersés sur tout le tablespace. Chaque fois que vous réorganisez un objet, vous allez probablement remplir certains de ces morceaux, mais en laisser d&rsquo;autres vides là où se trouvait l&rsquo;objet avant.</p>
<p>Fondamentalement, il est rare que ce type de fragmentation pose un problème, parce que cet espace vide n&rsquo;entraîne pas de travail supplémentaire, sauf lorsque on fait un <i>backup</i> du fichier. Si vous pensez que le temps passé à copier cet espace vide lors d&rsquo;un <i>backup</i> a un impact important sur la durée de la sauvegarde (dans le cas où le backup dépasse la fenêtre de temps permise avant le prochain cycle de chargement de données, par exemple), alors vous pouvez prévoir de déplacer des objets de telle sorte que l&rsquo;espace libre se trouve à la fin de fichiers. Cela permet ensuite de réduire la taille des fichiers: voir par exemple cette note sur la <a href="http://jonathanlewis.wordpress.com/2010/02/06/shrink-tablespace/">réduction de la taille des tablespaces</a> <ins>(en anglais)</ins>.<br />
Par contre, il faut garder à l&rsquo;esprit qu&rsquo;il peut y avoir des effets indésirables lors de cette réorganisation. Il y avait cette question sur le forum OTN il y a quelques années où un DBA s&rsquo;est aperçu que déplacer des tables les a rendu plus volumineuses. j&rsquo;ai écrit une <a href="http://jonathanlewis.wordpress.com/2007/11/23/table-rebuilds/">note</a> <ins>(en anglais)</ins> à propose de cela, en reprenant la question et la réponse (réponse que j&rsquo;avais publiée dans &lsquo;Practical Oracle 8i&rsquo;).</p>
<p>Les difficultés liées à cette fragmentation &lsquo;gruyère&rsquo; on été en grande partie un effet secondaire du paramètre PCTINCREASE d&rsquo;Oracle qu&rsquo;on pouvait spécifier pour les segments de données, amplifié par l&rsquo;idée reçue qu&rsquo;il vaut mieux réduire les objets à un seul <em>extent</em>. Mais depuis l&rsquo;introduction des tablespaces dont l&rsquo;espace libre est géré localement (<em>LMT &#8211; Locally Managed Tablespaces</em>), qui simplifient les options de dimensionnement des <em>extents</em> (surtout pour la taille d&rsquo;extent UNIFORM), la seule question est <strong>quand</strong> l&rsquo;espace libéré va être réutilisé et non <strong>comment</strong> est gérée cette réutilisation.</p>
<p>Pour en lire un peu plus là dessus: une <a href="http://jonathanlewis.wordpress.com/2008/07/01/ancient-history/">histoire ancienne</a> que j&rsquo;ai publié bien avant qu&rsquo;Oracle n&rsquo;introduise les <em>Locally Managed Tablespaces</em> avec une taille d&rsquo;extent uniforme, republié il y a 2 ans.</p>
<p><ins>La suite: <a href="http://blog.developpez.com/pachot/p9193/auteurs/jl-fragmentation-3/">Fragmentation &#8211; Table</a> </ins></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Verrous et signification du mode (lock mode), par Jonathan Lewis</title>
		<link>https://blog.developpez.com/pachot/jl_locks/</link>
		<comments>https://blog.developpez.com/pachot/jl_locks/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 07:19:25 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>
		<category><![CDATA[locks]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article est la traduction d&#8217;un article de Jonathan Lewis publié sur son blog. L&#8217;article original en anglais se trouve ici. Pour une description complète des modes de verrous, vous pouvez lire aussi: Les verrous sur les table, et leurs &#8230; <a href="https://blog.developpez.com/pachot/jl_locks/">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 Jonathan Lewis publié sur son blog. L&rsquo;article original en anglais se trouve <a href="http://jonathanlewis.wordpress.com/2010/06/21/locks/">ici</a>.<br />
<br />
Pour une description complète des modes de verrous, vous pouvez lire aussi: <a href="http://blog.developpez.com/pachot/p9048/auteurs/franck-pachot/fp-locks/">Les verrous sur les table, et leurs modes (S/X/RS/RX/SRX)</a><br />
</ins></p></blockquote>
<p>A propos des verrous (<em>locks</em>) et de leur <em>mode </em> (dans les colonnes LMODE et REQUEST de la vue V$LOCK par exemple), je raisonne souvent avec leur numéro. Et je m&rsquo;apercois que je n&rsquo;arrive jamais à retenir la correspondance entre le numéro et le lien, sauf pour le mode 6 = <em>exclusive</em>. Donc j&rsquo;ai finalement mis ici la table de correspondance pour que je puisse la retrouver facilement.</p>
<p><span id="more-16"></span></p>
<table border="1" width="100%">
<tr>
<th>Numero</th>
<th>Nom(s)</th>
<th>Opérations sur la table(TM lock)</th>
</tr>
<tr>
<td align="center">0</td>
<td>No lock</td>
<td>n/a</td>
</tr>
<tr>
<td align="center">1</td>
<td>Null lock (NL)</td>
<td>n/a</td>
</tr>
<tr>
<td align="center">2</td>
<td>Sub-share (SS)<br />Row-share (RS ou Row-S)</td>
<td>
<ul>
<li>select for update <em>(versions &lt; 9.2.0.1)</em></li>
<li>Intégrité référentielle, du côté opposé lors d&rsquo;un DML <em>(versions &ge; 9.2.0.5)</em></li>
<li>Lock table in row share mode</li>
<li>Lock table in share update mode</li>
</ul>
</td>
</tr>
<tr>
<td align="center">3</td>
<td>Sub-exclusive(SX)<br />Row-exclusive(RX ou Row-X)</td>
<td>
<ul>
<li>Mise à jour</li>
<li>select for update <em>(versions &ge; 9.2.0.1)</em></li>
<li>Lock table in row exclusive mode</li>
<li>Intégrité référentielle, du côté opposé lors d&rsquo;un DML <em>(versions &ge; 11.1 &#8211; cf <a href="http://jonathanlewis.wordpress.com/2010/02/15/lock-horror/">Lock Horror</a>)</em> </li>
</ul>
</td>
</tr>
<tr>
<td align="center">4</td>
<td>Share (S)</td>
<td>
<ul>
<li>Lock table in share mode</li>
<li>Peut apparaître en parallel DML avec ID2=1</li>
<li> Symptôme classique du verrouillage d&rsquo;une <em>foreign key</em> non indexée</li>
</ul>
</td>
</tr>
<tr>
<td align="center">5</td>
<td>share sub exclusive (SSX)<br />share row exclusive (SRX)</td>
<td>
<ul>
<li>Lock table in share row exclusive mode</li>
<li>symptôme plus rare du verrouillage de la <em>foreign key</em></li>
</ul>
</td>
</tr>
<tr>
<td align="center">6</td>
<td>Exclusive (X)</td>
<td>
<ul>
<li>Lock table in exclusive mode</li>
</ul>
</td>
</tr>
</table>
<p>Evidemment, c&rsquo;st un peu irritant que certains modes de verrous aient 2 noms et 2 abréviations. Et certains documents utilisent un nom avec l&rsquo;autre abréviation (par exemple pen parlant des row-exclusives, puis de l&rsquo;abréviation SX). Les fichiers de traces relatifs aux <em>locks</em> on tendance à utiliser SS, SX, and SSX plutôt que RS, RX and SRX.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Le ROWID et la place qu&#8217;il prend, par Jonathan Lewis</title>
		<link>https://blog.developpez.com/pachot/jl_rowid/</link>
		<comments>https://blog.developpez.com/pachot/jl_rowid/#comments</comments>
		<pubDate>Tue, 15 Jun 2010 19:18:25 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>
		<category><![CDATA[data_object_id]]></category>
		<category><![CDATA[objd]]></category>
		<category><![CDATA[object_id]]></category>
		<category><![CDATA[objn]]></category>
		<category><![CDATA[rowid]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article est la traduction d&#8217;un article de Jonathan Lewis publié sur son blog. L&#8217;article original en anglais se trouve ici. Le ROWID identifie un enregistrement d&#8217;une table dans la base de données, à partir de l&#8217;adresse physique du bloc &#8230; <a href="https://blog.developpez.com/pachot/jl_rowid/">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 Jonathan Lewis publié sur son blog. L&rsquo;article original en anglais se trouve <a href="http://jonathanlewis.wordpress.com/2010/05/09/rowid/">ici</a>.</p>
<p>Le <strong>ROWID </strong> identifie un enregistrement d&rsquo;une table dans la base de données, à partir de l&rsquo;adresse physique du bloc et du numéro d&rsquo;enregistrement dans le bloc. Il est utilisé principalement dans les indexes pour pointer sur l&rsquo;enregistrement de la table, et dans les tables pour les pointeurs des <em>chained rows</em>. C&rsquo;est le moyen le plus direct car il permet d&rsquo;aller directement sur le bloc qui contient l&rsquo;enregistrement.</p>
<p>Jusqu&rsquo;à Oracle 7, l&rsquo;adresse physique d&rsquo;un bloc était constitué du numéro du fichier de la base (absolute file_number, AFN ou FILE_ID ou FILE#) et du numéro de bloc relatif au fichier (block_number ou BLOCK_ID ou BLOCK#). L&rsquo;ensemble est appelé DBA: Data Block Address. Le ROWID utilise cela pour identifier le bloc, et y ajoute le numéro d&rsquo;enregistrement dans le bloc (ROW_NUMBER ou ROW#).</p>
<p>A partir d&rsquo;Oracle 8, l&rsquo;identification des fichiers est relative au tablespace. Cela permet de supporter plus de fichiers dans une base, et de rendre les tablespaces plus indépendants. On parle alors de numéro de fichier relatif à la tablespace (relative file_number, RFN ou RELATIVE_FNO ou RFILE#). Avec le numéro de bloc relatif au fichier, l&rsquo;ensemble constitue le RDBA: Relative Data Block Address. Pour les <em>bigfile tablespaces</em>, ne comportant qu&rsquo;un seul fichier, il s&rsquo;agit seulement du block#.<br />
Pour trouver un bloc dans la base, il est donc nécessaire de connaître aussi le tablespace. Plutôt que d&rsquo;ajouter le numéro de tablespace dans le ROWID, c&rsquo;est le DATA_OBJECT_ID (DATAOBJ# ou OBJD ou OBJ ou OBJECT_NUMBER) qui est utilisé. Il s&rsquo;agit de l&rsquo;identifiant de l&rsquo;objet physique, c&rsquo;est à dire du segment, contrairement à l&rsquo;OBJECT_ID (OBJ# ou OBJN) qui est l&rsquo;identifiant de l&rsquo;objet logique. Le DATA_OBJECT_ID permet d&rsquo;identifier le tablespace grâce au dictionnaire, puisque un segment se trouve dans un et un seul tablespace. <br />Ainsi, le ROWID ne comprends que des informations physiques pour identifier le bloc (segment, datafile, block). C&rsquo;est ce qui rend optimal les tablespaces transportables ainsi que l&rsquo;échange de partitions, car ils n&rsquo;ont pas à modifier le contenu des blocs mais seulement les méta-données du dictionnaire.</p>
<p>L&rsquo;ancien ROWID est appelé le <em>Restricted ROWID</em>, il est affiché sous la forme block#.row#.file# et celui qui inclut le data_objet_id est appelé <em>Extended ROWID</em>, il est affiché encodé (6 caractères pour dataobj#, 9 caractères pour file#/block#, 3 caractères pour row#). </p>
<p>Cet article de Jonathan Lewis explique la taille nécessaire au stockage du ROWID dans différents cas, ce qui peut être utile pour estimer la taille d&rsquo;un index par exemple.<br />
</ins></p></blockquote>
<p>Dans une récente discussion sur le <b><i><a href="http://hoopercharles.wordpress.com/2010/04/29/how-much-space-is-required-to-store-a-whole-lot-of-nothing/">blog un article de Charles Hooper</a></i></b> , j&rsquo;ai fait un commentaire disant qu&rsquo;il est difficile d&rsquo;être précis et non-ambigu lorsqu&rsquo;on estime l&rsquo;espace nécessaire au stockage du <b><i>ROWID.</i></b> Je vais donc essayer d&rsquo;énumérer tous les cas possible que l&rsquo;on peut rencontrer. Franchement, je ne suis pas sûr d&rsquo;être exhaustif dès le premier jet. </p>
<p>Alors, quelle place prend un <b>ROWID</b> ?<br />
<span id="more-15"></span><br />
Disons que je suis un enregistrement d&rsquo;une table normale (<em>heap table</em> &#8211; nous n&rsquo;allons pas prendre en compte le cas des <b>IOT</b>, tables organisées comme des indexes, parce que leurs enregistrements sont adressés par la clé primaire et non par le <em>ROWID</em>). Alors je me trouve dans un bloc de données, et ce bloc enregistre dans son entête le <strong>data object id</strong>, le <strong>relative file number</strong>, et le <strong>block id</strong>. C&rsquo;est la première composante de mon adresse. La seule autre ichose qui m&rsquo;est nécessaire de connaître est le numéro de l&rsquo;entrée que j&rsquo;occupe dans la liste des enregistrements du bloc(<b><i>row directory</i></b>) Et comme le <em>row directory</em> peut contenir jusqu&rsquo;à 4096 entrées, ce numéro prends 2 octets. Donc &#8211; de mon point de vue &#8211; la taille de mon rowid est de <b><i>deux octets</i></b> seulement.</p>
<p>Mais qu&rsquo;en est-il des autres personnes qui ont besoin de mon adresse ? Combien d&rsquo;espace doivent-ils allouer pour stocker mon ROWID ? Techniquement, ils ont besoin du <strong>data object id</strong> (pour leur permettre de trouver le numéro du tablespace), du numéro de fichier dans le tablespace (<strong><em>relative file number</em></strong>), du numéro de bloc dans le fichier (<strong><em>block number</em></strong>), et du numéro de l&rsquo;entrée dans le <em>row directory</em> (<strong>row number</strong>). Il s&rsquo;agit de 4 octets pour le <em>data object id</em>, 2 octets pour le <em>row number</em>. Le numéro de bloc et le numéro de fichier sont stockés ensembles sur 4 octets.<br />
Il y a deux formats pour cette dernière partie:</p>
<ul>
<li>Pour les &lsquo;bigfile tablespaces&rsquo; qui n&rsquo;ont toujours qu&rsquo;un seul fichier par tablespace, les 4 octets sont tous utilisés pour le numéro de bloc.</li>
<li>Pour les tablespaces traditionnels, 10 bits sont réservés pour le numéro relatif de fichier ce qui permet jusqu&rsquo;à 1022 fichiers par tablespace, et le reste est pour le numéro de bloc dans le fichier.</li>
</ul>
<p>Donc dans le cas général, un rowid prends <b><i>dix octets</i></b>.</p>
<p>Mais différentes parties du code peuvent se comporter différemment, plus ou mois efficaces pour la gestion de l&rsquo;espace.</p>
<p>Si mon <em>rowid</em> est stocké dans une autre table, dans une colonne de type ROWID (ce qui est très souvent une mauvaise idée), ou s&rsquo;il est stocké temporairement dans une variable d&rsquo;un programme de type ROWID alors la table ou la variable va devoir stocker les <b><i>dix octets.</i></b></p>
<p>Pour l&rsquo;utilisateur final, le <em>rowid</em> doit être affiché sous forme lisible de sorte que le <em>rowid</em> de dix octets est transformé en une chaîne de <b><i>18 caractères.</i></b></p>
<p>Si mon <em>rowid</em> doit être stockée dans un index de ma table, alors il y a plusieurs cas.</p>
<p>Si la table n&rsquo;est <b>pas partitionnée,</b> alors le code interne peut déduire mon <strong>data object id</strong> du fait que l&rsquo;index ne peut pointer que sur le segment de ma table. Du coup, l&rsquo;index n&rsquo;a pas à stocker les 4 octets du <strong>data object id</strong>.</p>
<p>Dans ce cas, si c&rsquo;est un <strong>index unique</strong> alors le <em>rowid</em> est stocké comme une valeur de taille fixe, associée à la clé primaire, et il prends <b><i>6 octets.</i></b> Si l&rsquo;index n&rsquo;est <strong>pas unique</strong>, alors le <em>rowid</em> est stocké comme une colonne supplémentaire à la fin de l&rsquo;index. Toute valeur de colonne est précédée par un octet qui donne sa taille (length byte). Ce qui veut dire que la taille nécessaire à son stockage est de <b><i>7 octets</i></b>.</p>
<p>Si ma table est une <b>table partitionnée,</b> alors la même logique de déduction du <strong>data object id</strong> peut toujours s&rsquo;appliquer pour un <strong>index local</strong>: Par définition, la partition <code class="codecolorer text default"><span class="text">n</span></code> de l&rsquo;index local pointe obligatoirement vers la partition <code class="codecolorer text default"><span class="text">n</span></code> de la table. Donc de la même manière, suivant que l&rsquo;index est unique ou non, le stockage est toujours de <b><i>6 ou 7 octets.</i></b> </p>
<p>Mais si c&rsquo;est un <strong>index global</strong> ou global/partitionné, alors n&rsquo;importe quelle entrée de l&rsquo;index peut pointer sur n&rsquo;importe quelle partition de la table. Dans ce cas, l&rsquo;entrée d&rsquo;index doit inclure les 4 octets du <strong>data object id</strong> de la partition dans laquelle se trouve l&rsquo;enregistrement. Et dans ce cas, suivant que l&rsquo;index est unique ou non, la taille du rowid est de <b><i>10 ou 11 octets.</i></b></p>
<p>Je pense cela couvre à peu près tous les cas. Mais si vous voulez vous creuser un peu la tête, vous pouvez réfléchir à ce qu&rsquo;il se passe dans un index cluster et si cela introduit un type de rowid différent.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Temps passé en file d&#8217;attente, par Jonathan Lewis.</title>
		<link>https://blog.developpez.com/pachot/jl_queue_time/</link>
		<comments>https://blog.developpez.com/pachot/jl_queue_time/#comments</comments>
		<pubDate>Mon, 17 May 2010 19:58:37 +0000</pubDate>
		<dc:creator><![CDATA[pachot]]></dc:creator>
				<category><![CDATA[Jonathan Lewis]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Cet article est la traduction d&#8217;un article de Jonathan Lewis publié sur son blog. L&#8217;article original en anglais se trouve ici. J&#8217;ai traduit récemment un article de Doug Burns sur un concept très important lorsqu&#8217;on étudie les performances d&#8217;un système: &#8230; <a href="https://blog.developpez.com/pachot/jl_queue_time/">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 Jonathan Lewis publié sur son blog. L&rsquo;article original en anglais se trouve <a href="http://jonathanlewis.wordpress.com/2009/09/03/queue-time/">ici</a>.</p>
<p>J&rsquo;ai traduit récemment un article de Doug Burns sur un concept très important lorsqu&rsquo;on étudie les performances d&rsquo;un système: améliorer le <strong>temps de réponse</strong> d&rsquo;un traitement individuel, et améliorer le <strong>débit (<em>throughput</em>)</strong> d&rsquo;un ensemble de traitement sont 2 objectifs différents, et souvent contradictoires.</p>
<p>Doug Burns donnait un exemple concret en différenciant la mesure du temps de réponse d&rsquo;une session individuelle (<em>response time</em>) et la mesure du débit d&rsquo;une charge globale (<em>throughput</em>). Jonathan Lewis montre ici de manière simple la théorie qu&rsquo;il y a derrière. Pour aller plus loin dans la théorie, je traduirais prochainement les commentaires de Cary Millsap là dessus.<br />
</ins></p></blockquote>
<p> Je n&rsquo;ai pas l&rsquo;intention de rentrer dans la technique des files d&rsquo;attentes (<em>Queuing Theory</em>) qui est plutôt le domaine de Cary Millsap, mais je voudrais juste donner un exemple pour montrer de quelle manière la théorie des files d&rsquo;attentes (<em>Queues</em>) s&rsquo;applique à Oracle, en répondant à la question suivante que m&rsquo;a posé un client récemment:</p>
<p><i> &laquo;&nbsp;Comment peuvent-ils se plaindre que le temps de réponse a empiré, alors que le débit (throughput) global a augmenté de 5% ?&nbsp;&raquo;</i></p>
<p>La réponse malheureusement est: oui, bien sûr, le temps de réponse est peut-être pire et ceci vient justement du fait que le débit est meilleur, et je vais donner un exemple dans cette note, construit pour montrer comment cela peut se produire.<br />
<span id="more-14"></span></p>
<ul>
<li>Supposons que vous ayez une machine avec une seule CPU.</li>
<li>Supposons que vous ayez deux programmes  en parallèle, qui se réveillent périodiquement pour faire un certain travail.</li>
<li>Le programme 1 exécute une tâche qui utilise 0,1 secondes de CPU (et aucune d&rsquo;autre ressource). Il produit un résultat de N (unités de mesure de la production). Et il se réveille toutes les secondes pour s&rsquo;exécuter.</li>
<li>Le programme 2 exécute une tâche qui utilise 0,5 secondes de CPU (et aucune autres ressource), produit un résultat 5N (5 fois plus important que le programme 1), et se réveille toutes les cinq secondes pour s&rsquo;exécuter.</li>
</ul>
<p>Sur une durée de dix secondes, chaque programme (s&rsquo;exécutant tout seul sur la machine) utilise 10% de CPU et produit 10N unités de production, et le temps de réponse est égal au temps CPU. </p>
<p>Mais que se passe-t-il lorsque les deux programme démarrent à peu près en même temps ?</p>
<p>Si vous êtes chanceux le programme 2 va commencer son travail peu de temps après que le programme 1 ne vienne de terminer le sien, et il va terminer à son tour son travail peu de temps avant le programme 1 ne recommence sa prochaine exécution.</p>
<p>Si vous n&rsquo;avez pas cette chance les deux programme vont commencer à faire leur travail en même temps, et un seul d&rsquo;entre eux aura la CPU. A ce moment là, une machine typique va utiliser des tranches de temps pour faire comme si les 2 programme s&rsquo;exécutaient simultanément. Donc les 2 programme vont commencer à s&rsquo;échanger la CPU (<em>context switching</em>), disons toutes les 0,01 secondes. La conséquence de cela (à peu près), c&rsquo;est que le programme 1 va terminer son travail au bout de 0,2 secondes (0,1 pour travailler en CPU et 0,1 pour attendre) et que le programme 2 va terminer son travail au bout de 0,6 secondes (0,5 secondes de CPU et 0,1 d&rsquo;attente &#8211; puisque le programme concurrent a passé 0,1 seconde en CPU).</p>
<p>Les temps de réponse se sont dégradés, et de manière spectaculaire dans le cas du programme 1. Nous avons beaucoup de CPU inutilisée (80%, en fait), mais le temps de réponse de chaque job va être très variable en fonction du moment ou arrivent les jobs.</p>
<p>Dans le cas de mon client, il y avait beaucoup plus de programme comme le programme 1 qui étaient en train de d&rsquo;exécuter, et qui faisaient passer beaucoup plus de tâches de 0,1 secondes en utilisant la capacité disponible de la machine. Donc le débit (throughput) était amélioré, mais cela augmentait la probabilité que ces programme entre en collision avec celui de 0,5 secondes (ou même entre eux) et donc le temps de réponse individuel s&rsquo;est dégradé.</p>
<p>Pour passer de mon exemple trivial à un modèle plus réaliste correspondant au monde réel, vous avez besoin de la théorie des files d&rsquo;attentes (<em>queuing theory</em>). J&rsquo;ai rendu mon exemple aussi simple que possible avec un taux d&rsquo;arrivée fixe, pour deux tâches de durée fixe, se déclenchant à intervalles réguliers. Pour modéliser le monde réel, vous devez prendre en compte des tâches de durée variable, qui arrivent à des intervalles répartis de manière aléatoire &#8211; et les calculs seront alors un peu plus complexes.</p>
<p>Mais vous n&rsquo;avez pas besoin de ces détails mathématiques pour en comprendre les conséquences importantes:
<ul>
<li>le temps de réponse peut varier considérablement en fonction de l&rsquo;heure d&rsquo;arrivée, et ce même si la machine est loin chargée au maximum,</li>
<li> et temps de réponse peut se détériorer, même si (ou peut-être parce que) le débit s&rsquo;améliore.</li>
</ul>
<p>Pour de plus amples commentaires sur le dilemme temps de réponse/débit, voir <b><i><a href="http://blog.developpez.com/pachot/p8917/auteurs/doug-burns/db-throughput/">cet article par Doug Burns</a></i></b> .</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
