<?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>Cap Data Team SGBD Blog : Oracle, SQL Server, MySQL, Sybase... &#187; internals</title>
	<atom:link href="http://blog.capdata.fr/index.php/tag/internals/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.capdata.fr</link>
	<description>Le blog technique sur les bases de données de CAP DATA Consulting</description>
	<lastBuildDate>Wed, 01 Feb 2012 17:21:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Error 8976 / 8978, problèmes de chaînage, comment récupérer les données</title>
		<link>http://blog.capdata.fr/index.php/error-8976-8978-problemes-de-chainage-comment-recuperer-les-donnees/</link>
		<comments>http://blog.capdata.fr/index.php/error-8976-8978-problemes-de-chainage-comment-recuperer-les-donnees/#comments</comments>
		<pubDate>Mon, 30 May 2011 22:17:34 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[corruption]]></category>
		<category><![CDATA[dbcc ind]]></category>
		<category><![CDATA[internals]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=2400</guid>
		<description><![CDATA[Cet article fait suite à une question postée sur developpez.net la semaine dernière. La personne indique qu&#8217;une erreur 823 est remontée sur une base en version SQL Server 2000. On lui demande d&#8217;inspecter les logs systèmes à la recherche d&#8217;une panne matérielle qui aurait pu être à l&#8217;origine du problème, puis de retourner le résultat [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article fait suite à une <a href="http://www.developpez.net/forums/d1087285/bases-donnees/ms-sql-server/administration/error-i-o-msg-823-a/">question </a>postée sur <em>developpez.net</em> la semaine dernière. La personne indique qu&#8217;une erreur 823 est remontée sur une base en version SQL Server 2000. On lui demande d&#8217;inspecter les logs systèmes à la recherche d&#8217;une panne matérielle qui aurait pu être à l&#8217;origine du problème, puis de retourner le résultat d&#8217;un DBCC CHECKDB sur la base:</p>
<pre><span style="color: #008000;">Msg*8909, Niveau*16, État*1, Ligne*1
Erreur de TABLE : Objet ID = 0, INDEX ID*=*0, page ID = (1:22988). ID de page de l'en-tête
de page = (0:0).
CHECKDB a trouvé 0 erreurs d'allocation et 1 erreurs de cohérence non associées à un
quelconque objet UNIQUE.
Msg*8928, Niveau*16, État*1, Ligne*1
Objet ID = 574885365, INDEX ID = 0 : <span style="color: #ff0000;">La page (1:22988) ne peut pas être traitée</span>. Pour
plus d'informations, consultez les autres erreurs.
<span style="color: #ff0000;">Msg*8976, Niveau*16, État*1, Ligne*1</span>
Erreur de table : Objet ID = 574885365, index ID = 1. <span style="color: #ff0000;">Page (1:22988) n'a pas été trouvé
dans l'analyse bien que ses parents (1:22930) et (1:22987) précédents y font référence</span>.
Contrôlez toutes les erreurs précédentes.
<span style="color: #ff0000;">Msg*8978</span>, Niveau*16, État*1, Ligne*1
Erreur de table : Objet ID = 574885365, index ID = 1. <span style="color: #ff0000;">La page (1:22989) n'a pas de référence
dans la page précédente (1:22988). Possibilité d'un problème de liaison de chaîne.</span>
CHECKDB a trouvé 0 erreurs d'allocation et 3 erreurs de cohérence dans la TABLE
'XXXXXXXX' (objet ID = 574885365).
CHECKDB a trouvé 0 erreurs d'allocation et 4 erreurs de cohérence dans la base de
données 'xxxxxxx'.
<span style="color: #ff0000;">repair_allow_data_loss </span>est le minimum de niveau de réparation pour les erreurs trouvés
par DBCC CHECKDB (chantier ).</span></pre>
<p>Outre le fait qu&#8217;un problème matériel empêche tout bonnement la lecture d&#8217;une page depuis le disque, le CHECKDB indique deux autres erreurs 8978 et 8976, parlant d&#8217;un problème de liaison de page. On rappelle que chaque page de données ou d&#8217;index hors pages spéciales (IAM, DBINFO, SGAM, GAM, PFS, ML, DM,&#8230;) est liée à la page qui la précède et à la page qui la suit dans le plan d&#8217;allocation, mais aussi à une page parente dans un index.</p>
<p>Lorsqu&#8217;une page parente référence une page à un niveau inférieur du B-tree et que cette page n&#8217;est pas trouvée, alors DBCC CHECKDB renvoie une erreur 8976. Lorsqu&#8217;une page référence une page Next et que cette page n&#8217;est pas trouvée, alors DBCC CHECKDB renvoie une erreur 8978. Mais ces messages n&#8217;indiquent pas s&#8217;il ne s&#8217;agit que d&#8217;une corruption de l&#8217;entête de la page, ou aussi des données.</p>
<p>Ce qui veut dire que les données peuvent être bonnes alors que DBCC CHECKDB nous oriente vers un repair_allow_data_loss comme méthode de résolution, avec les conséquences que l&#8217;on sait (désallocation de la page qui pose problème et perte des données).</p>
<p>Dans le cas évoqué sur <em>developpez.net</em>, la personne ne dispose pas de backup, la question est de savoir quelles données il risque de perdre, et si les données ne sont pas endommagées, comment peut-il les récupérer.</p>
<h2>Repro pour ce problème</h2>
<p>Nous allons créer une base linkcorrupt et modifier la valeur du pointeur prevPageID dans une page de niveau feuille d&#8217;un index cluster pour forcer des erreurs 8976 et 8978.</p>
<pre><span style="color: #0000ff;">create database linkcorrupt
GO
use linkcorrupt
GO
</span><span style="color: #0000ff;">create table T1(
     a numeric identity,
     b char(4000) default replicate('b',4000),
     c bigint default round(rand()*100,0))
GO
insert into T1 default values
GO 1000
create unique clustered index IDX_T1C on T1(a)</span><span style="color: #0000ff;">
GO
</span></pre>
<p>On va choisir une page du niveau feuille de l&#8217;index cluster (le dbcc ind a été purgé de certaines colonnes pour une meilleure lisibilité)</p>
<pre><span style="color: #0000ff;">dbcc ind('linkcorrupt','T1',-1)</span></pre>
<pre><span style="color: #0000ff;"> PageFID PagePID     PageType  IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
 ------- ----------- --------  ---------- ----------- ----------- ----------- -----------
<span style="color: #808080;"> 1       90          10        NULL       0           0           0           0</span>
<span style="color: #ff6600;"> 1       110         2         1          1           115         0           0
 1       115         2         1          0           0           1           110
 1       121         2         2          0           0           0           0</span>
 1       672         1         0          1           673         0           0
 1       673         1         0          1           674         1           672
<span style="color: #ff0000;"> 1       674         1         0          1           675         1           673</span>
 1       675         1         0          1           676         1           674
 1       676         1         0          1           677         1           675
 1       677         1         0          1           678         1           676
 1       678         1         0          1           679         1           677
 1       679         1         0          1           680         1           678
 1       680         1         0          1           681         1           679
 ...
</span></pre>
<p>De ce résultat on déduit que:</p>
<ul>
<li>La page 1:90 est la page IAM pour T1.</li>
<li>La page 1:121 est la page racine de l&#8217;index cluster</li>
<li>Les pages 1:110 et 1:115 sont des pages de niveau intermédiaire pour l&#8217;index cluster (on aura volontairement casé deux lignes par page pour augmenter le feuillage de l&#8217;index).</li>
<li>Les autres pages sont les pages du niveau feuille de l&#8217;index cluster. On choisira de corrompre le pointeur prevPagePID dans la page 1:674. Comme l&#8217;index vient juste d&#8217;être construit, il est parfaitement clusterisé et les pages avant et après sont respectivement 1:673 et 1:675. On passe la base hors-ligne et on ouvre le fichier MDF dans <a href="http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm">xvi32</a>.</li>
</ul>
<pre><span style="color: #0000ff;">alter database linkcorrupt set offline</span></pre>
<p>La page 1:674 se trouve à l&#8217;offset 0&#215;544000 dans le fichier mdf  (674*8192). Il est alors aisé de repérer les offset où sont stockés les pointeurs prev et next:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2011/05/linkcorrupt.jpg"><img class="alignnone size-large wp-image-2421" title="linkcorrupt" src="http://blog.capdata.fr/wp-content/uploads/2011/05/linkcorrupt-1024x290.jpg" alt="" width="1024" height="290" /></a></p>
<p>Le trait rouge représente l&#8217;offset 0 de la page 1:674. Les 96 premiers octets constituent l&#8217;entête de la page. x86 étant en little-endian, l&#8217;octet de poids faible est en premier donc il faut lire à l&#8217;envers. 02A1 représente notre page prev 1:673, 02A3 notre page next 1:675 et 02A2 notre PageID. On décide de zéro-initialiser l&#8217;octet de poids faible de 673 :</p>
<p style="text-align: center;"><a href="http://blog.capdata.fr/wp-content/uploads/2011/05/linkcorrupt2.jpg"><img class="size-full wp-image-2426 aligncenter" title="linkcorrupt2" src="http://blog.capdata.fr/wp-content/uploads/2011/05/linkcorrupt2.jpg" alt="" width="251" height="78" /></a></p>
<p>On repasse alors la base en ligne et on contrôle notre base pour vérifier qu&#8217;elle se trouve bien dans l&#8217;état attendu:</p>
<pre><span style="color: #0000ff;">alter database linkcorrupt set online
GO
dbcc checkdb ('linkcorrupt') with no_infomsgs, all_errormsgs
GO

<span style="color: #008000;">Msg 8928, Niveau 16, État 1, Ligne 1
ID d'objet 2073058421, ID d'index 1, ID de partition 72057594038386688,  ID d'unité d'allocation 72057594043367424 (type In-row data) :
<span style="color: #ff0000;">impossible de traiter la page (1:674)</span>. Pour plus d'informations,  consultez les autres erreurs.
Msg 8939, Niveau 16, État 98, Ligne 1
Erreur de table : ID d'objet 2073058421, ID d'index 1, ID de partition  72057594038386688, ID d'unité d'allocation 72057594043367424
(type  In-row data), page (1:674). Échec du test (IS_OFF (BUF_IOERR,  pBUF-&gt;bstat)). Valeurs 12716041 et -4.
<span style="color: #ff0000;">Msg 8976</span><span style="color: #ff0000;">, Niveau 16, État 1, Ligne 1</span>
Erreur de table : ID d'objet 2073058421, ID d'index 1, ID de partition  72057594038386688, ID d'unité d'allocation 72057594043367424
(type  In-row data). <span style="color: #ff0000;">La page (1:674) n'a pas été détectée lors de l'analyse  alors que sa page parent (1:110) et les (1:673) pages précédentes
la  référencent</span>. Vérifiez les erreurs précédentes.
<span style="color: #ff0000;">Msg 8978, Niveau 16, État 1, Ligne 1</span>
Erreur de table : ID d'objet 2073058421, ID d'index 1, ID de partition  72057594038386688, ID d'unité d'allocation 72057594043367424
(type  In-row data). <span style="color: #ff0000;">Une référence de la page précédente (1:674) est manquante à  la page (1:675)</span>. Un problème de liaison de chaîne s'est
peut-être  produit.
CHECKDB a trouvé 0 erreurs d'allocation et 4 erreurs de cohérence dans la table 'T1' (ID d'objet 2073058421).
CHECKDB a trouvé 0 erreurs d'allocation et 4 erreurs de cohérence dans la base de données 'linkcorrupt'.
repair_allow_data_loss est le niveau minimum de réparation pour les erreurs trouvées par DBCC CHECKDB (linkcorrupt).</span></span></pre>
<h2>Identifier les plages de valeurs concernées par la corruption:</h2>
<p>Une des questions qu&#8217;on peut se poser, comment savoir ce qu&#8217;il y a à récupérer (si les données ne sont pas touchées) ou ce qu&#8217;on va potentiellement perdre (si les données sont touchées).</p>
<p>Avant cela, il faut déjà récupérer tout le reste de la table en injectant les données jusqu&#8217;à la page 1:673 comprise et à partir de la page 1:675 comprise, puis d&#8217;inspecter la page 1:674 pour voir si les données qui y sont contenues sont lisibles. On sait que les pages sont classées physiquement dans l&#8217;ordre de notre clé clusterisée, donc il suffit pour exclure l&#8217;intervalle compris dans la page 1:674, de connaître la dernière valeur de &#8216;a&#8217; dans la page 1:673 et la première valeur de &#8216;a&#8217; dans la page 1:675.</p>
<p>On créé deux tables temporaires pour stocker le résultat des dbcc page sur les deux pages prev et next:</p>
<pre><span style="color: #0000ff;">CREATE TABLE #recover673 (parentobject varchar(50), Object varchar(100), Field varchar(50), Value varchar(max))
GO
INSERT INTO #recover673  exec ('dbcc page(10,1,673,3) with tableresults')
GO</span></pre>
<pre><span style="color: #0000ff;">CREATE TABLE #recover675 (parentobject varchar(50), Object varchar(100), Field varchar(50), Value varchar(max))
GO
INSERT INTO #recover675  exec ('dbcc page(10,1,675,3) with tableresults')
GO</span></pre>
<p>C&#8217;est la table d&#8217;offset de ligne qui permet de retourner les lignes dans l&#8217;ordre, dans les faits les lignes ne sont pas nécessairement classées physiquement dans la page. On se sert des slots pour connaître la dernière valeur de &#8216;a&#8217; dans la page 1:673 et la première dans la page 1:675 (on rappelle qu&#8217;on n&#8217;a que deux lignes par page).</p>
<pre><span style="color: #0000ff;">select Object, Value FROM #recover673 where Field='a'
Object                                    Value
--------------------------------------  ---------
Slot 0 Column 0 Offset 0x4 Length 9        3
<span style="color: #ff0000;">Slot 1 Column 0 Offset 0x4 Length 9        4</span>
</span></pre>
<pre><span style="color: #0000ff;">select Object, Value FROM #recover675 where Field='a'

Object                                    Value
--------------------------------------  ---------
<span style="color: #ff0000;">Slot 0 Column 0 Offset 0x4 Length 9        7</span>
Slot 1 Column 0 Offset 0x4 Length 9        8</span></pre>
<p>Il s&#8217;agit donc des valeurs de clé 5 et 6 qui sont dans la page qui pose problème. On créé une table à l&#8217;identique et on injecte les deux plages de valeurs [0;4] et [7;1000]:</p>
<pre><span style="color: #0000ff;">select * into T1_backup from T1 where 1=2
GO
insert into T1_backup select a,b from T1 <span style="color: #008000;">with (index = IDX_T1C)</span> where a in (1,2,3,4)
GO
insert into T1_backup select a,b from T1 <span style="color: #008000;">with (index = IDX_T1C)</span> where a &gt;=7
GO</span></pre>
<p>En vert, un hint qui permet de forcer un seek sur l&#8217;index clusterisé. En effet, un Clustered Index Scan aurait tenté de lire les pages 1:673 -&gt; 1:674 et aurait remonté une erreur de chaînage et une erreur 824.</p>
<p>Il ne reste plus qu&#8217;à essayer de lire le contenu de la page endommagée pour voir ce qu&#8217;il peut y avoir de récupérable:</p>
<pre><span style="color: #0000ff;">CREATE TABLE #recover674 (parentobject varchar(50), Object varchar(100), Field varchar(50), Value varchar(max))
GO
insert into #recover674  exec ('dbcc page(17,1,674,3) with tableresults')
GO

</span></pre>
<p>Si la page est lisible alors une requête simple permet de ramener les valeurs au format de T1:</p>
<pre><span style="color: #0000ff;">with TA as (select cast(Object as char(6)) SlotID, Value from #recover674 where Field='a'),
TB as (select cast(Object as char(6)) SlotID, Value from #recover674 where Field='b')
</span><span style="color: #0000ff;">insert into T1_backup</span> <span style="color: #0000ff;">select TA.Value as 'a', TB.value as 'b' from TA inner join TB on TA.SLotID = TB.SlotID
<span style="color: #008000;">
a      b
-------------------------------
5      bbbbbbbbbbbbbbbbbbb(...)
6      bbbbbbbbbbbbbbbbbbb(...)</span></span></pre>
<p>Dans le cas où les données ne sont pas lisibles, on a au moins l&#8217;information de la plage qui est perdue, information que ne donne pas le repair_allow_data_loss.</p>
<p>A+. David B.<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/msg-2508-level-16-state-1-the-in-row-data-for-object-is-incorrect/" rel="bookmark" title="10 mai 2011">Msg 2508, Level 16, State 1: the In-Row data %% for object %% is incorrect</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/regenerer-le-ddl-des-indexes-full-text/" rel="bookmark" title="12 octobre 2011">Regénérer le DDL des indexes FULL TEXT</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/suppression-accidentelle-de-ligne-comment-retrouver-le-coupable/" rel="bookmark" title="6 octobre 2011">Suppression accidentelle de ligne : comment retrouver le coupable ?</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/alter-table-rebuild/" rel="bookmark" title="2 mars 2011">Alter table rebuild</a> (Louis HOCHBERG) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/point-in-time-recovery-et-fn_dump_dblog/" rel="bookmark" title="13 juillet 2011">Point-in-time recovery et fn_dump_dblog()</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.894 ms -->
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Ferror-8976-8978-problemes-de-chainage-comment-recuperer-les-donnees%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Ferror-8976-8978-problemes-de-chainage-comment-recuperer-les-donnees%2F&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/error-8976-8978-problemes-de-chainage-comment-recuperer-les-donnees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Planification dans Adaptive Server</title>
		<link>http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/</link>
		<comments>http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 13:39:46 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[Sybase]]></category>
		<category><![CDATA[internals]]></category>
		<category><![CDATA[scheduling]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=159</guid>
		<description><![CDATA[Un petit post sur la planification de tâches sur Adaptive Server.
Globalement, ASE utilise des threads pour supporter toutes les tâches qu&#8217;il exécute: requêtes, IO réseau ou disque, connexions utilisateur, tâches internes&#8230; en conjonction avec son propre planificateur de tâche.
Le rôle du planificateur de tâche sur tout système est de partager le temps d&#8217;un CPU entre [...]]]></description>
			<content:encoded><![CDATA[<p>Un petit post sur la planification de tâches sur Adaptive Server.</p>
<p>Globalement, ASE utilise des threads pour supporter toutes les tâches qu&#8217;il exécute: requêtes, IO réseau ou disque, connexions utilisateur, tâches internes&#8230; en conjonction avec son propre planificateur de tâche.</p>
<p>Le rôle du planificateur de tâche sur tout système est de partager le temps d&#8217;un CPU entre plusieurs unités d&#8217;exécution (tâches). Il existe deux grandes familles de planificateurs, les <strong>préemptifs</strong>, et les <strong>coopératifs</strong>.</p>
<p>Le planificateur <strong>préemptif </strong>a le pouvoir de planifier et d&#8217;interrompre les tâches selon des règles qui lui sont propres et sans tenir compte du type de tâche en cours d&#8217;exécution. <em>One size fits all</em>, comme on dit.  Ce mécanisme, qui garantit qu&#8217;aucune tâche ne va monopoliser les ressources CPU, permet à chaque programme de pouvoir avoir la main sur la CPU à un moment où un autre. Sur la plupart des OS (linux, UNIX System V et Windows NT à partir de la 4.0), le planificateur alloue au thread un bail d&#8217;exécution ou un quantième. Si la tâche n&#8217;a pas terminé son travail dans le temps imparti, elle est interrompue. Lorsqu&#8217;il interrompt la tâche en cours, le planificateur sauvegarde son contexte dans un coin (c&#8217;est à dire les structures process + thread qui la représentent en mémoire), et planifie une nouvelle tâche sur la CPU. Ce qu&#8217;on appelle un<em> changement de contexte</em>.</p>
<p>Le planificateur <strong>coopératif</strong>, lui, va au contraire laisser à la tâche le soin de se terminer toute seule. C&#8217;est là la plus grosse différence, il n&#8217;interrompt pas une tâche qui n&#8217;a pas terminé son travail.  C&#8217;est à la charge de la tâche de rendre la main pour laisser de la place aux autres, c&#8217;est donc à elle de prévoir un mécanisme de relâche (<em>to yield</em> = &laquo;&nbsp;céder&nbsp;&raquo;). Windows 3.1 employait un scheduler coopératif, les Windows 98 et 95 aussi pour assurer la compatibilité avec les programmes 16 bits.</p>
<p>Maintenant, on imagine facilement le risque d&#8217;employer un tel système de planification: une tâche qui part en vrille ne libèrera jamais la CPU, ça n&#8217;a donc plus été employé pour faire des operating systems.</p>
<p><a href="http://www.csail.mit.edu/user/1547">Micheal Stonebraker</a> avait publié un article de quelques pages au début des années 80* expliquant en gros que les &#8217;services&#8217; apportés par UNIX system V n&#8217;étaient pas adaptés au monde de la base de données, et notamment en matière de planification. Les tâches typiques issues des SGBD prennent plus de temps à s&#8217;effectuer car il ne s&#8217;agit pas de calcul mais d&#8217;IOs, et le mode préemptif n&#8217;est pas adapté car il &#8216;coupe&#8217; la dynamique et l&#8217;efficacité du SGBD en produisant de nombreux changements de contexte.</p>
<p>Donc les développeurs chez Sybase ont répondu en créant un scheduler coopératif &#8216;<em>on top</em>&#8216; **, propre à Adaptive Server et par dessus le planificateur de l&#8217;OS, de telle manière à ce qu&#8217;il masque les choses vis à vis de celui-ci et limite au maximum les changements de contexte.</p>
<p><strong>- Les tranches de temps:</strong><br />
ASE va donc fonctionner comme un OS, mais avec ses règles à lui: il gère sa propre planification, son propre partage du temps CPU, ses propres valeurs de quantième. Car bien que coopératif, il doit pouvoir stopper une tâche qui ne répond plus et éviter la saturation d&#8217;un engine. Lorsqu&#8217;il planifie une tâche, il va lui allouer un bail. Ce bail n&#8217;est pas une valeur temporelle, c&#8217;est un nombre de ticks d&#8217;horloge qui est décrémenté. Il est calculé en divisant le paramètre &#8216;timeslice&#8217; par &#8217;sql server clock tick length&#8217;. Comme les deux valeurs sont à 100 ms par défaut, le nombre de ticks d&#8217;horloge autorisé est de 1. Dans le déroulement de son exécution, une tâche va passer par des parties de code qu&#8217;on appelle des <em>yield points</em>, au cours desquels elle va prendre une seconde pour vérifier qu&#8217;elle n&#8217;a pas dépassé son bail. Si elle découvre que le bail est excédé (bail &lt; 0), elle va demander à ASE de lui accorder une grace supplémentaire (<em>cpu grace time</em>), qui peut aller jusqu&#8217;à  500 ticks (soit 50 secondes). Si elle n&#8217;a pas terminé au delà de cette valeur, alors ASE sort les gros moyens, termine la tâche, annule ses transactions et affiche une stacktrace dans l&#8217;errorlog:</p>
<pre>00:00000:00005:2007/04/02 22:09:24.07 kernel  timeslice -501, current process infected
00:00000:00005:2007/04/02 22:09:24.75 kernel  ************************************
00:00000:00005:2007/04/02 22:09:24.77 kernel  curdb = 1 tempdb = 2 pstat = 0x200
00:00000:00005:2007/04/02 22:09:24.77 kernel  lasterror = 0 preverror = 0 transtate = 1
00:00000:00005:2007/04/02 22:09:24.77 kernel  curcmd = 0 program =
...</pre>
<p>Tout ceci se passe toujours sans que l&#8217;OS ne sache rien, car de son côté, le processus dataserver est toujours en exécution. C&#8217;est le but: l&#8217;OS ne doit pas interrompre le processus dataserver puisque celui-ci semble toujours travailler.</p>
<p><strong>- Runnable Process search count:</strong><br />
Toujours dans le souci de préserver son exécution vis à vis de l&#8217;OS, lorsqu&#8217;il a terminé d&#8217;exécuter des tâches, et plutôt que de rendre la main tout de suite, Adaptive Server va entrer dans une boucle de vérification des IOs en attente côté réseau puis côté disque. S&#8217;il ne trouve rien, il va tourner (<em>spinning</em>) pour rechercher de nouvelles tâches en attente d&#8217;exécution, puis de nouvelles IOs réseau, puis de nouvelles IOs disques, etc&#8230; tout ça 2000 fois par défaut (<em>runnable process search count</em>), même s&#8217;il n&#8217;y a rien à traiter dans aucune file d&#8217;attente. Ce qui donne une apparente sensation d&#8217;hyperactivité côté OS, alors que côté Adaptive Sever, l&#8217;électro-encéphalo est plutôt plat.</p>
<p>Pour illustrer tout ça, une petite explication de la section &#8216;kernel&#8217; de sp_sysmon:</p>
<pre>Kernel Utilization
------------------

Your Runnable Process Search Count is set to 5000
and I/O Polling Process Count is set to 10

Engine Busy Utilization        CPU Busy   I/O Busy       Idle
------------------------       --------   --------   --------
Engine 0                       80.0 %      7.5 %     12.5 %
Engine 1                       80.8 %      6.0 %     13.2 %
Engine 2                       82.5 %      5.7 %     11.9 %
Engine 3                       84.0 %      6.7 %      9.3 %
Engine 4                       79.0 %      6.8 %     14.2 %
Engine 5                       80.0 %      7.3 %     12.7 %
Engine 6                       79.6 %      8.3 %     12.0 %
------------------------       --------   --------   --------
Summary           Total         565.9 %     48.4 %     85.7 %
Average                         80.8 %      6.9 %     12.2 %</pre>
<p>Avant de commencer, il faut bien rappeler le cheminement de la boucle:<br />
<a href="https://www.alldb.fr/blog/wp-content/uploads/2009/06/rpsc3.png"><img class="alignnone size-medium wp-image-178" src="https://www.alldb.fr/blog/wp-content/uploads/2009/06/rpsc3-300x140.png" alt="" /></a><a href="https://www.alldb.fr/blogs/wp-content/uploads/2009/06/rpsc2.png"><br />
</a></p>
<p>Chaque engine tient le compte de ticks reçus de l&#8217;OS (par le biais de signaux SIGALRM) tous les 100ms, et les répertorie   selon trois catégories:</p>
<p><strong>CPU Busy</strong>: représente le temps (en fait le nombre de ticks ramené en pourcentage) passé par l&#8217;engine à exécuter une tâche sur l&#8217;intervalle.<br />
<strong>Idle</strong>: représente le temps passé par l&#8217;engine à n&#8217;exécuter aucune tâche sur l&#8217;intervalle.<br />
<strong> I/O Busy</strong>: est une soustraction de Idle. Il s&#8217;agit du temps passé par l&#8217;engine à n&#8217;exécuter aucune tâche (donc Idle) mais où il y avait au moins une IO disque en attente dans la file. Elle représente donc la quantité de temps où l&#8217;engine n&#8217;a pas pu exécuter une tâche parce qu&#8217;il y avait au moins une IO disque en attente.</p>
<p>On peut retrouver ces valeurs brutes en interrogeant les variables globales @@cpu_busy, @@idle, et @@io_busy. La durée d&#8217;un tick peut être retrouvée avec @@timeticks.</p>
<p>A+. [ David B. ]</p>
<p><em>*: Michael Stonebraker, Operating System Support for Database Management, CACM 24(7), p412-418 (1981).<br />
**: et Microsoft fit de même </em><em>en dotant </em><em>SQL Server 7.0  de son propre scheduler coopératif (UMS), toujours bien présent en version 2008 sous une autre dénomination (SQLOS). </em></p>
<p> <script type="text/javascript" src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/formation-optimisation-de-requetes/" rel="bookmark" title="22 septembre 2010">Formation Optimisation de requêtes</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/certification-sql-server-70-432-offerte/" rel="bookmark" title="25 février 2011">Voucher certification SQL Server 70-432 offert !</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/scruter-les-journaux-devenements-windows-avec-logparser/" rel="bookmark" title="12 mars 2010">Scruter les journaux d&#8217;évènements Windows avec LogParser</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/abonnez-vous-au-blog-de-la-capdata-team/" rel="bookmark" title="23 juin 2010">Abonnez-vous au blog de la CapData team !</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/interet-de-creer-des-indexes-cluster-uniques/" rel="bookmark" title="16 mars 2010">Intérêt de créer des indexes cluster uniques</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.085 ms -->
<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsybase-ase-planification-dans-adaptive-server%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsybase-ase-planification-dans-adaptive-server%2F&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

