<?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; journal de transactions</title>
	<atom:link href="http://blog.capdata.fr/index.php/tag/journal-de-transactions/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>Suppression accidentelle de ligne : comment retrouver le coupable ?</title>
		<link>http://blog.capdata.fr/index.php/suppression-accidentelle-de-ligne-comment-retrouver-le-coupable/</link>
		<comments>http://blog.capdata.fr/index.php/suppression-accidentelle-de-ligne-comment-retrouver-le-coupable/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 10:50:28 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[journal de transactions]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=3019</guid>
		<description><![CDATA[C&#8217;est vrai qu&#8217;il y a des outis, Change Data Capture et tout l&#8217;arsenal des Database Audit Specifications. Mais pour retrouver qui a supprimé les lignes dans la table T1 le 17 septembre dernier entre 12h00 et 14h00 il y a encore plus simple, pour peu qu&#8217;il y ait des backups de transactions.
La fonction qui tue:
Dans [...]]]></description>
			<content:encoded><![CDATA[<p>C&#8217;est vrai qu&#8217;il y a des outis, Change Data Capture et tout l&#8217;arsenal des Database Audit Specifications. Mais pour retrouver qui a supprimé les lignes dans la table T1 le 17 septembre dernier entre 12h00 et 14h00 il y a encore plus simple, pour peu qu&#8217;il y ait des backups de transactions.</p>
<h2>La fonction qui tue:</h2>
<p>Dans un article <a href="http://blog.capdata.fr/index.php/point-in-time-recovery-et-fn_dump_dblog/">précédent</a>, nous avons couvert une fonction table valuée fort intéressante qui permet de relire à l&#8217;intérieur d&#8217;une sauvegarde de journal: <strong>fn_dump_dblog()</strong>. Nous allons nous en servir pour connaître cette fois l&#8217;identité du coupable. La table concernée par le DELETE est la table T1, il faut commencer par récupérer sa valeur de allocation_unit_id:</p>
<pre><span style="color: #0000ff;">select allocation_unit_id from sys.allocation_units AU inner join sys.partitions P
on P.hobt_id = AU.container_id where P.object_id = object_id('T1')</span></pre>
<pre><span style="color: #3366ff;"><em>allocation_unit_id
---------------------
72057594043301888
</em></span></pre>
<p>Ensuite, rechercher dans les backups transactionnels des opérations de suppression de lignes sur cet objet:</p>
<pre><span style="color: #0000ff;">select [Current LSN] ,Operation ,[Transaction ID] ,AllocUnitId
from fn_dump_dblog(DEFAULT, DEFAULT,DEFAULT, DEFAULT,
'<span style="color: #ff0000;">C:\UTRECHT\MSSQL.1\MSSQL\Backup\demorecovery.TRAN2.bak</span>',
DEFAULT,DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT,DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT,DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT,DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT,DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT) where Operation  = '<span style="color: #ff0000;">LOP_DELETE_ROWS</span>' and AllocUnitId = <span style="color: #ff0000;">72057594043301888

</span></span><span style="color: #3366ff;"><em>Current LSN             Operation          Transaction ID AllocUnitId         
----------------------- ------------------ -------------- --------------------
00000025:00000032:0003  LOP_DELETE_ROWS    <span style="color: #ff0000;">0000:00000a9d </span> 72057594043301888   
00000025:00000032:0005  LOP_DELETE_ROWS    <span style="color: #ff0000;">0000:00000a9d</span>  72057594043301888   
00000025:00000032:0006  LOP_DELETE_ROWS    <span style="color: #ff0000;">0000:00000a9d</span>  72057594043301888   
00000025:00000032:0007  LOP_DELETE_ROWS    <span style="color: #ff0000;">0000:00000a9d</span>  72057594043301888   
00000025:00000032:0008  LOP_DELETE_ROWS    <span style="color: #ff0000;">0000:00000a9d</span>  72057594043301888   </em></span>
<span style="color: #3366ff;">...</span></pre>
<p>On récupère le LSN de la transaction pour retrouver le BEGIN TRAN correspondant:  <span style="color: #ff0000;"><em>0000:00000a9d</em>:</span></p>
<pre><span style="color: #0000ff;">select [Current LSN] ,Operation ,[Transaction ID] ,AllocUnitId
 ,[Begin Time] ,[Transaction Name] ,[End Time] ,[Description]
 ,[Transaction SID]
from fn_dump_dblog(DEFAULT, DEFAULT,DEFAULT, DEFAULT,
'<span style="color: #ff0000;">C:\UTRECHT\MSSQL.1\MSSQL\Backup\demorecovery.TRAN2.bak</span>',
DEFAULT,DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
where Operation  = '<span style="color: #ff0000;">LOP_BEGIN_XACT</span>' and [Transaction ID] = '<span style="color: #ff0000;">0000:00000a9d</span>'</span>

<span style="color: #3366ff;">Current LSN             Operation                       Transaction ID AllocUnitId        
----------------------- ------------------------------- -------------- --------------------
00000025:00000032:0001  LOP_BEGIN_XACT                  0000:00000a9d  NULL                

</span></pre>
<pre><span style="color: #3366ff;"> Begin Time               Transaction Name                  Description                                  
------------------------ --------------------------------- -----------------------------------------------
2011/10/05 15:21:50:510  tralalala                         tralalala;<span style="color: #ff0000;">0x75a770d73d6bf54bb0dc07725254ae57</span>    </span><span style="color: #ff0000;">

</span></pre>
<pre><span style="color: #3366ff;">Transaction SID
------------------------------------
<span style="color: #ff0000;">0x75A770D73D6BF54BB0DC07725254AE57</span></span></pre>
<p>Remarque intéressante, [Transaction SID] (en rouge) correspond au SID de l&#8217;utilisateur dans la base&#8230;</p>
<h2>Le dénouement&#8230;</h2>
<p>Il ne reste plus qu&#8217;à dégainer la requête sur sys.database_principals:</p>
<pre><span style="color: #0000ff;">select name from sys.database_principals where sid = <span style="color: #ff0000;">0x75A770D73D6BF54BB0DC07725254AE57</span></span></pre>
<pre><em><span style="color: #3366ff;">name
</span><span style="color: #3366ff;">-------------------
user1

</span></em><em></em></pre>
<p>A+<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<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>
<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/error-8976-8978-problemes-de-chainage-comment-recuperer-les-donnees/" rel="bookmark" title="30 mai 2011">Error 8976 / 8978, problèmes de chaînage, comment récupérer les données</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/how-to-reduire-la-taille-du-journal-de-transactions-sur-disque/" rel="bookmark" title="11 juillet 2011">How-To: réduire la taille du journal de transactions sur disque</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>
</ul>
<p><!-- Similar Posts took 3.451 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%2Fsuppression-accidentelle-de-ligne-comment-retrouver-le-coupable%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsuppression-accidentelle-de-ligne-comment-retrouver-le-coupable%2F&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/suppression-accidentelle-de-ligne-comment-retrouver-le-coupable/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Modes de récupération et journal de transactions, épisode 2</title>
		<link>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/</link>
		<comments>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/#comments</comments>
		<pubDate>Thu, 11 Dec 2008 17:09:55 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[bulk logged]]></category>
		<category><![CDATA[journal de transactions]]></category>

		<guid isPermaLink="false">http://192.168.1.220:8080/blogs/sqlserver/?p=5</guid>
		<description><![CDATA[Dans l&#8217;article précédent, nous avons vu quels sont les principaux modes de récupération SIMPLE et FULL, et leur effet respectif sur le journal des transactions.
Ici nous allons aborder le troisième mode BULK-LOGGED, ses avantages, inconvénients et contextes d&#8217;utilisation. Quelques rappels du post précédent:
BULK-LOGGED: c&#8217;est un mode à combiner avec le mode FULL. Dans ce mode, [...]]]></description>
			<content:encoded><![CDATA[<p>Dans l&#8217;article précédent, nous avons vu quels sont les principaux modes de récupération SIMPLE et FULL, et leur effet respectif sur le journal des transactions.</p>
<p>Ici nous allons aborder le troisième mode BULK-LOGGED, ses avantages, inconvénients et contextes d&#8217;utilisation. Quelques rappels du post précédent:</p>
<p><strong>BULK-LOGGED: </strong>c&#8217;est un mode à combiner avec le mode FULL. Dans ce mode, les opérations de modification de masse ne sont pas complètement journalisées, et l&#8217;impact de telles opérations sur le journal est limité. Le fait de changer de FULL à BULK-LOGGED ne modifie en rien ma façon de sauvegarder mes bases. En mode BULK-LOGGED, mes sauvegardes transactionnelles horaires continuent de s&#8217;exécuter sans problème. Très utile lorsqu&#8217;on lance notre réorganisation des indexes hebdomadaire car on gagne un temps fou.</p>
<p>Quelles sont ces opérations de modification de masse:</p>
<ol>
<li>SELECT INTO</li>
<li>BCP IN / BULK INSERT</li>
<li>ALTER INDEX  &#8230; REBUILD</li>
<li>Manipulation de champs de type TEXT:</li>
</ol>
<p>On les appelle parfois par abus de langage opérations <em>non loggées</em>, le terme plus juste est <em>minimallement loggées</em>.</p>
<p class="MsoNormal">Lorsqu’une de ces opérations <em>minimalement loggée </em>est exécutée, seules les allocations de pages sont journalisées, mais elles seules ne suffisent pas à restaurer l’intégralité de mon reindex ou de mon select into en cas de crash. C’est pourquoi pour permettre de restaurer ces données modifiées, la sauvegarde embarque avec elle les pages de données allouées lors de l’opération.</p>
<p class="MsoNormal">Pour le vérifier, on se propose de comparer sous les deux modes de récupération FULL et BULK_LOGGED, deux opérations minimalement loggées :</p>
<ol>
<li>Un SELECT INTO d&#8217;une table de 2,6 millions de lignes dans une table d’archive.</li>
<li>Le rebuild d’un index clusterisé sur une table de 2,6 millions de lignes.</li>
</ol>
<p class="MsoNormal">Dans chaque cas, nous allons mesurer plusieurs choses :</p>
<ol>
<li> Le temps d’exécution de l’opération.</li>
<li>L’impact sur le journal de transactions (en Mb).</li>
<li>L’impact sur la taille de ma sauvegarde de transaction (en Mb).</li>
</ol>
<p class="MsoNormal"><!--[if !supportLists]--><strong><span>1)<span> </span></span><span dir="ltr">En mode de récupération FULL :</span></strong><!--[endif]--></p>
<p class="MsoNormal">Pour pouvoir exécuter la sauvegarde du journal à l’issue de chaque opération, il faut commencer par exécuter une sauvegarde complète (voir article <a title="recovery models, episode 1" href="https://www.alldb.fr/blogs/?p=5">précédent</a>) :</p>
<pre><span>ALTER DATABASE CAPDATA SET RECOVERY FULL

BACKUP DATABASE CAPDATA TO DISK='C:\YUKON\BACKUP\CAPDATA.bak'
WITH init, stats</span></pre>
<p class="MsoNormal">Ensuite on va vérifier que l’on part sur un journal vide :</p>
<pre><span>dbcc sqlperf(logspace)</span>

<span>Database Name        Log Size (MB) Log Space Used (%) Status
----------------------------------------------------------------------------------------------
CAPDATA            49,99219      2,951633           0</span></pre>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">Le journal fait 50Mb, il est vide (2%). On peut donc lancer le SELECT INTO :</p>
<pre><span>set statistics time on
select * into PIECEAPPARTEMENT2 from PIECEAPPARTEMENT
</span></pre>
<pre><span><span> SQL Server parse and compile time: </span></span></pre>
<pre><span><span><span> </span>CPU time = 0 ms, elapsed time = 48 ms.</span></span></pre>
<pre><span><span> <span> </span>SQL Server Execution Times:</span></span></pre>
<pre><span><span><span> </span>CPU time = 7641 ms,<span> </span>elapsed time = <strong>57673</strong> ms.</span></span></pre>
<pre><span><span> (<strong>2644317</strong> row(s) affected)</span></span></pre>
<p class="MsoNormal">Quelle est la taille du journal ?</p>
<pre><span><span lang="EN-GB">dbcc</span><span lang="EN-GB"> sqlperf(logspace)</span></span></pre>
<pre><span><span>
Database Name        Log Size (MB) Log Space Used (%) Status
----------------------------------------------------------------------------------------------
</span></span></pre>
<pre><span><span>CAPDATA<span> </span>            97,55469<span>       </span>93,43568<span> </span><span>           </span>0
</span></span></pre>
<p class="MsoNormal">
<p class="MsoNormal">Il est passé de 50 à 97 Mb, et il est plein. Sauvegardons la transaction pour le vider :</p>
<pre><span><span lang="EN-GB">BACKUP</span><span lang="EN-GB"> LOG CAPDATA <span>TO</span> DISK=<span>'C:\YUKON\BACKUP\CAPDATA.trn'</span> <span>with</span> init, stats</span></span></pre>
<pre><span><span lang="EN-GB">
(…)</span></span></pre>
<pre><span><span lang="EN-GB">BACKUP LOG successfully processed 11592 pages in 25.525 seconds (3.720 MB/sec).</span></span></pre>
<p class="MsoNormal">11592 * 8192 ~= <strong>93 Mb</strong>, soit la taille de ma transaction dans mon journal. Normal. Une fois la sauvegarde effectuée, on repart sur un journal vide. On peut donc lancer immédiatement le REBUILD de l’index sur PIECEAPPARTEMENT :</p>
<pre><span><span lang="EN-GB">ALTER</span><span lang="EN-GB"> <span>INDEX</span> PK_PIECEAPPARTEMENT <span>ON</span> PIECEAPPARTEMENT REBUILD WITH</span><span lang="EN-GB"> (SORT_IN_TEMPDB = <span>ON</span>)</span></span></pre>
<pre><span><span>
 SQL Server Execution Times:</span></span></pre>
<pre><span><span lang="EN-GB"><span> </span>CPU time = 11828 ms,<span> </span>elapsed time = <strong>66788</strong> ms.</span></span></pre>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">A nouveau le journal est plein et si je le sauvegarde encore, la taille du fichier sera égale à la taille de ma transaction.</p>
<pre><span><span lang="EN-GB">dbcc</span><span lang="EN-GB"> sqlperf(logspace)</span></span></pre>
<pre><span lang="EN-GB">
 <span>Database Name<span> </span>     Log Size (MB)     Log Space Used (%)    Status</span></span></pre>
<pre><span><span lang="EN-GB">----------------------------------------------------------------------------------------------</span></span></pre>
<pre><span><span>CAPDATA<span> </span>            97,55469<span>          </span>92,42763<span>               </span>0</span></span></pre>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal"><strong><span>2)<span> </span></span><span dir="ltr">En mode de récupération BULK_LOGGED :</span></strong><!--[endif]--></p>
<p class="MsoNormal">Même scénario mais cette fois la base est passée en mode de récupération BULK_LOGGED, et mon journal est vide. Pour partir sur la même enveloppe initiale, et ne pas fausser les résultats pour le SELECT INTO, je vais réduire la taille de mon journal à sa taille de départ (50Mb) :</p>
<pre><span><span>dbcc</span><span> shrinkfile(<span>'CAPDATA_log01'</span>,50)</span></span></pre>
<pre><span><span lang="EN-GB">
DbId<span> </span>  FileId<span>   </span>    CurrentSize MinimumSize UsedPages<span> </span>   EstimatedPages</span></span></pre>
<pre><span><span>------ ----------- ----------- ----------- ----------- --------------</span></span></pre>
<pre><span><span>6<span> </span>     2<span> </span>       6400<span> </span>          6400<span> </span><span> </span>      6400<span> </span>         6400</span></span></pre>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">Et je lance le SELECT INTO :</p>
<pre><span><span lang="EN-GB">
SQL Server Execution Times:</span></span></pre>
<pre><span><span lang="EN-GB"><span> </span>CPU time = 8235 ms,<span> </span>elapsed time = <strong>24353</strong> ms.</span></span></pre>
<pre><span><span> (<strong>2644317</strong> row(s) affected)</span></span></pre>
<p class="MsoNormal">
<p class="MsoNormal">Déjà, il a mis deux fois moins de temps. Voyons voir la situation du journal :</p>
<pre><span><span>dbcc</span><span> sqlperf(logspace)</span></span></pre>
<pre><span><span lang="EN-GB">
 Database Name<span> </span>Log Size (MB) Log Space Used (%) Status</span></span></pre>
<pre><span><span lang="EN-GB">----------------------------------------------------------------------------------------------</span></span></pre>
<pre><span><span>CAPDATA<span> </span>      49,99219<span>      </span>3,073722<span>             </span>0</span></span></pre>
<p class="MsoNormal">
<p class="MsoNormal">Quasiment rien n’a été utilisé !! Non seulement l’enveloppe n’a pas bougé mais en plus mon journal est toujours quasiment vide. J’en profite pour regarder ce qui se trouve dans ces 3% de<span> </span>journal utilisé:</p>
<p class="MsoNormal">
<pre><span lang="EN-GB">select</span><span lang="EN-GB"> Operation, COUNT(*) nr_records, SUM([Log Record Length]) totalsize</span></pre>
<pre><span lang="EN-GB">from</span><span lang="EN-GB"> <span>::</span>fn_dblog(<span>null</span>,<span>null</span>) </span></pre>
<pre><span lang="EN-GB">group</span><span lang="EN-GB"> <span>by</span> Operation <span>order</span> <span>by</span> COUNT(*) <span>desc</span></span></pre>
<pre><span lang="EN-GB"> </span></pre>
<pre><span lang="EN-GB">Operation<span>                       </span>nr_records<span> </span> totalsize</span></pre>
<pre><span lang="EN-GB">------------------------------- ----------- -----------</span></pre>
<pre><span lang="EN-GB">LOP_SET_FREE_SPACE</span><span lang="EN-GB"><span>             </span></span><span lang="EN-GB"><span> </span>11111<span> </span>      577772</span></pre>
<pre><span lang="EN-GB">LOP_SET_BITS<span>                    </span>5650<span> </span>       328272</span></pre>
<pre><span lang="EN-GB">LOP_MODIFY_ROW<span>                  </span>1570<span> </span>       138852</span></pre>
<pre><span lang="EN-GB">LOP_COUNT_DELTA<span>                 </span>33<span> </span>         6864</span></pre>
<pre><span lang="EN-GB">LOP_BUF_WRITE<span>                   </span>31<span> </span>         59512</span></pre>
<pre><span lang="NL">LOP_INSERT_ROWS<span>                 </span>27<span> </span>         4068</span></pre>
<pre><span lang="NL">LOP_ROOT_CHANGE<span>                 </span>5<span> </span>          480</span></pre>
<pre><span lang="NL">LOP_BEGIN_XACT<span>                  </span>4<span> </span>          432</span></pre>
<pre><span lang="NL">LOP_HOBT_DELTA<span>                  </span>4<span> </span>          256</span></pre>
<pre><span lang="NL">LOP_COMMIT_XACT<span>                 </span>4<span> </span>          208</span></pre>
<pre><span lang="NL">LOP_LOCK_XACT<span>                   </span>3<span> </span>          120</span></pre>
<pre><span lang="NL">LOP_HOBT_DDL<span>                    </span>2<span> </span>          72</span></pre>
<pre><span lang="EN-GB">LOP_PREP_XACT<span> </span><span>                  </span>1<span> </span>          68</span></pre>
<pre><span lang="EN-GB">LOP_END_CKPT<span>                    </span>1<span> </span>          136</span></pre>
<pre><span lang="NL">LOP_FORMAT_PAGE<span>                 </span>1<span> </span>          84</span></pre>
<pre><span lang="NL">LOP_BEGIN_CKPT<span>                  </span>1<span> </span>          96</span></pre>
<pre><span>LOP_CREATE_ALLOCCHAIN<span>           </span>1<span> </span>          40</span></pre>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">L’opérateur logique LOP_SET_FREE_SPACE est typiquement un opérateur d’allocation, qui met à jour la page PFS du fichier de donnée et indique quels sont les pages qui ne sont plus libres pour de futures allocations car elles ont été utilisées par le SELECT INTO. Si je lance la sauvegarde de mon journal :</p>
<pre><span lang="EN-GB">
Processed 149 pages for database 'CAPDATA', file 'CAPDATA_log01' on file 1.</span></pre>
<pre><span lang="EN-GB">BACKUP LOG successfully processed 11277 pages in 28.242 seconds (3.270 MB/sec).</span></pre>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">La sauvegarde fait 90Mb alors qu’il n’y a que 1,5Mb de transactions dans mon journal, parce qu’elle embarque les pages de données allouées par le SELECT INTO.</p>
<p class="MsoNormal">Exécutons maintenant le rebuild de l’index :</p>
<pre><span lang="EN-GB">
ALTER</span><span lang="EN-GB"> <span>INDEX</span> PK_PIECEAPPARTEMENT <span>ON</span> PIECEAPPARTEMENT REBUILD WITH</span><span lang="EN-GB"> (SORT_IN_TEMPDB = <span>ON</span>)</span></pre>
<pre><span>
 SQL Server Execution Times:</span></pre>
<pre><span lang="EN-GB"><span> </span>CPU time = 11594 ms,<span> </span>elapsed time = <strong>48860 ms</strong>.</span></pre>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">48 secondes au lieu de 66, et dans le journal:</p>
<pre><span lang="EN-GB">
dbcc</span><span lang="EN-GB"> sqlperf(logspace)</span></pre>
<pre><span lang="EN-GB">
 Database Name<span>   </span>Log Size (MB)     Log Space Used (%) Status</span></pre>
<pre><span lang="EN-GB">----------------------------------------------------------------------------------------------</span></pre>
<pre><span>CAPDATA<span> </span>        49,99219<span>           </span><strong>5,8515</strong><span> </span>            0</span></pre>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal">
<p class="MsoNormal">Et la sauvegarde de journal fait 91 Mb, loin des 5% utilisés. Là encore, les pages de données créées lors du rebuild sont embarquées dans la sauvegarde.</p>
<p><strong>Conclusion</strong>: en mode BULK_LOGGED, pour pouvoir restaurer une opération minimalement loggée, le BACKUP LOG est obligé de prendre avec lui les pages de données allouées dans l&#8217;opération. Ici, on ne voit pas de différence de taille des sauvegardes de journal entre les modes FULL et BULK_LOGGED, mais si en plus des opérations minimalement loggées, j&#8217;ai des ordres de modifications standards type INSERT/DELETE,UPDATE, la taille de ma sauvegarde va croître (et le temps de sauvegarde avec) en BULK_LOGGED et dépasser la taille d&#8217;une sauvegarde en mode FULL. Donc attention à l&#8217;espace disponible  sur les disques de sauvegardes le week end pendant la reorg !</p>
<p>David B.</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/scripting-et-smo-suite-scripter-les-objets-directement-en-t-sql/" rel="bookmark" title="3 août 2010">Scripting et SMO (suite): scripter les objets directement en T-SQL</a> (David BAFFALEUF) [SQL Server]</li>
<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/regles-d%e2%80%99installation-de-base-episode-2/" rel="bookmark" title="6 janvier 2010">Règles d&#8217;installation de base (épisode 2)</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/how-to-reduire-la-taille-du-journal-de-transactions-sur-disque/" rel="bookmark" title="11 juillet 2011">How-To: réduire la taille du journal de transactions sur disque</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>
</ul>
<p><!-- Similar Posts took 3.190 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%2Fmodes-de-recuperation-et-journal-de-transactions-episode-2%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmodes-de-recuperation-et-journal-de-transactions-episode-2%2F&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modes de récupération et journal de transactions, épisode 1</title>
		<link>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/</link>
		<comments>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 12:16:18 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[journal de transactions]]></category>
		<category><![CDATA[mode de récupération]]></category>
		<category><![CDATA[Sauvegarde & Restauration]]></category>

		<guid isPermaLink="false">http://192.168.1.220:8080/blogs/sqlserver/?p=4</guid>
		<description><![CDATA[Une petite série de posts sur les différents modes de récupération des bases sous SQL Server 2005/2008, et leur impact sur le journal de transactions.
Dans ce premier épisode:

Qu&#8217;implique le passage de SIMPLE à COMPLET.
Que devient mon journal en mode COMPLET si je ne le sauvegarde pas régulièrement.

Le mode de récupération (recovery model en anglais) est [...]]]></description>
			<content:encoded><![CDATA[<p>Une petite série de posts sur les différents modes de récupération des bases sous SQL Server 2005/2008, et leur impact sur le journal de transactions.</p>
<p><strong>Dans ce premier épisode:</strong></p>
<ol>
<li>Qu&#8217;implique le passage de SIMPLE à COMPLET.</li>
<li>Que devient mon journal en mode COMPLET si je ne le sauvegarde pas régulièrement.</li>
</ol>
<p>Le mode de récupération (<em>recovery model</em> en anglais) est une propriété de base de données qui va préciser pour celle-ci deux choses essentielles:</p>
<ol>
<li>Le recyclage de l&#8217;espace consommé par les transactions validées dans son journal  de transactions.</li>
<li>La possibilité ou non de pouvoir sauvegarder ces transactions validées.</li>
</ol>
<p>Il existe trois modes de récupération: <strong>FULL</strong>,<strong> SIMPLE </strong>et <strong>BULK-LOGGED</strong>.</p>
<p><strong>FULL: </strong>c&#8217;est le mode par défaut. Dans ce mode, toutes les transactions sont journalisées, même les  opérations de modifications de masse (CREATE INDEX, BULK INSERT ou bcp.exe, SELECT INTO, et les opérations sur les champs TEXT). Dès l&#8217;instant où il y a eu au moins une sauvegarde complète sur la base, les transactions validées restent dans le journal. La seule façon de recycler l&#8217;espace occupé par ces transactions est de lancer régulièrement une sauvegarde du journal. Les transactions validées sont sauvegardées dans un fichier et sont alors supprimées du journal * .</p>
<p><strong>SIMPLE: </strong>dans ce mode, le recyclage des transactions validées est la responsabilité du checkpoint. En plus de flusher sur disque les pages de données modifiées dans le cache de données, le checkpoint supprime les transactions validées du journal sans les sauvegarder. Conséquence de celà, je n&#8217;ai pas la possibilité de sauvegarder mes transactions en mode SIMPLE. Je ne pourrai exécuter que des sauvegardes complètes ou différentielles (ou de fichier en lecture seule).</p>
<p><strong>BULK-LOGGED: </strong>c&#8217;est un mode à combiner avec le mode FULL. Dans ce mode, les opérations de modification de masse (citées plus haut) ne sont pas complètement journalisées, et l&#8217;impact de telles opérations sur le journal est limité. Le fait de changer de FULL à BULK-LOGGED ne modifie en rien ma façon de sauvegarder mes bases. En mode BULK-LOGGED, mes sauvegardes transactionnelles horaires continuent de s&#8217;exécuter sans problème. Très utile lorsqu&#8217;on lance notre réorganisation des indexes hebdomadaire car on gagne un temps fou.</p>
<table border="0">
<tbody>
<tr>
<td bgcolor="#dddddd"><em><strong>*: </strong>il existe au moins deux exceptions à cette règle: si la base est principale dans une session de miroir synchrone et que le site miroir est injoignable, où si la base est publiée dans le cadre d&#8217;une réplication transactionnelle et que la distribution ou l&#8217;agent de lecture du journal sont injoignables / inactifs. Dans ces deux cas, les transactions en attente (non envoyées au miroir, non écrites dans la base distribution) restent dans le journal et ne sont pas vidées par les sauvegardes de transactions.</em></td>
</tr>
</tbody>
</table>
<p><strong>Note: </strong>Attention à ne pas confondre mode de récupération FULL et sauvegarde FULL.</p>
<p><strong>Pour retrouver le mode de récupération d&#8217;une base:</strong></p>
<pre><span>SELECT</span><span> DATABASEPROPERTYEX(<span>'maBase'</span>,<span>'RECOVERY'</span>) <span>as</span> RECOVERYMODE</span></pre>
<p class="MsoNormal"><strong>Pour changer le mode d&#8217;une base:</strong></p>
<p class="MsoNormal">
<pre><span>ALTER</span><span> <span>DATABASE</span> maBase <span>SET</span> RECOVERY [ FULL | SIMPLE | BULK_LOGGED ]</span></pre>
<p class="MsoNormal">
<p><strong>1) Première remarque: il faudra obligatoirement (re)lancer une sauvegarde complète avant de sauvegarder le journal:</strong><br />
- Quand je créé ma base.<br />
- Quand je passe de SIMPLE à FULL.</p>
<p>La sauvegarde de transaction a besoin d&#8217;un numéro de transaction (LSN pour Log Sequence Number) de référence pour savoir à partir de quelle transaction commencer sa sauvegarde. Lorsqu&#8217;il n&#8217;y a pas eu d&#8217;autre sauvegarde de transactions avant elle, comme c&#8217;est le cas quand je passe de SIMPLE à FULL ou quand je viens de créer ma base, elle se base sur le LSN de fin de la dernière sauvegarde complète dans le même mode. Le fonctionnement précis de la sauvegarde à chaud fera l&#8217;objet d&#8217;un autre article prochainement.</p>
<p>Pour le mettre en évidence, créons-nous une petite base CRASHTEST:<br />
<span><br />
</span></p>
<pre><span>CREATE</span><span> <span>DATABASE</span> CRASHTEST</span></pre>
<pre><span>on</span><span> <span>PRIMARY</span></span></pre>
<pre><span>(NAME=<span>'CRASHTEST_data'</span>,</span></pre>
<pre><span>FILENAME=<span>'F:\KATMAI\MSSQL10.KATMAI\MSSQL\DATA\CRASHTEST_data.mdf'</span>,</span></pre>
<pre><span>SIZE=100MB, MAXSIZE=500MB)</span></pre>
<pre><span>LOG <span>ON</span></span></pre>
<pre><span>(NAME=<span>'CRASHTEST_log'</span>,</span></pre>
<pre><span>FILENAME=<span>'F:\KATMAI\MSSQL10.KATMAI\MSSQL\DATA\CRASHTEST_log.ldf'</span>,</span></pre>
<pre><span>SIZE=50MB,
MAXSIZE=500MB)</span></pre>
<p>Vérifions son mode de récupération:</p>
<pre><span>SELECT</span><span> DATABASEPROPERTYEX(<span>'CRASHTEST'</span>,<span>'RECOVERY'</span>) <span>as</span> RECOVERYMODE</span></pre>
<pre>RECOVERYMODE
---------------------------------------------------------
FULL</pre>
<p>Créons une petite transaction et essayons de la sauvegarder:</p>
<pre><span>use</span><span> CRASHTEST</span></pre>
<pre><span>create</span><span> <span>table</span> TABLE1 (A numeric <span>identity</span>, B varchar(5000))</span></pre>
<pre><span>insert</span><span> <span>into</span> TABLE1 <span>values</span> (replicate(<span>'b'</span>,5000))</span></pre>
<pre><span>backup</span><span> log CRASHTEST <span>to</span> disk=<span>'C:\CRASHTEST.log1.trn'</span> <span>with</span><span> </span>init, stats</span></pre>
<pre><span><em>Msg 4214, Level 16, State 1, Line 1</em></span></pre>
<pre><span><em>
BACKUP LOG cannot be performed because there is no current database backup.</em></span></pre>
<p><span><em> </em></span><br />
J&#8217;ai donc effectivement besoin d&#8217;avoir une sauvegarde complète pour initialiser ma chaîne:</p>
<pre><span>backup</span><span> <span>database</span> CRASHTEST <span>to</span> disk=<span>'C:\CRASHTEST.1.bak'</span> <span>with</span> init, stats</span></pre>
<pre><span><em>Processed 152 pages for database 'CRASHTEST', file 'CRASHTEST_data' on file 1.
100 percent processed.
Processed 1 pages for database 'CRASHTEST', file 'CRASHTEST_log' on file 1.
BACKUP DATABASE successfully processed 153 pages in 0.266 seconds (4.711 MB/sec).
</em></span></pre>
<p>OK, je retente de sauvegarder mon log:</p>
<pre><span>backup</span><span> log CRASHTEST <span>to</span> disk=<span>'C:\CRASHTEST.log1.trn'</span> <span>with</span><span> </span>init, stats</span></pre>
<pre><span><em>100 percent processed.</em></span></pre>
<pre><span><em>
Processed 6 pages for database 'CRASHTEST', file 'CRASHTEST_log' on file 1.</em></span></pre>
<pre><span><em>
BACKUP LOG successfully processed 6 pages in 0.161 seconds (0.283 MB/sec).</em></span></pre>
<p><span><em> </em></span><br />
Même problème lorsque je passe de SIMPLE à FULL:</p>
<pre><span>ALTER</span><span> <span>DATABASE</span> CRASHTEST <span>set</span> RECOVERY SIMPLE</span></pre>
<pre><span>ALTER</span><span> <span>DATABASE</span> CRASHTEST <span>set</span> RECOVERY <span>FULL</span></span></pre>
<pre><span>backup</span><span> log CRASHTEST <span>to</span> disk=<span>'C:\CRASHTEST.log2.trn'</span> <span>with</span> init, stats</span></pre>
<pre><span><em>Msg 4214, Level 16, State 1, Line 1
BACKUP LOG cannot be performed because there is no current database backup.</em></span></pre>
<p><strong>2) SAUVEGARDEZ VOS TRANSACTIONS !</strong></p>
<p>C&#8217;est un problème que l&#8217;on retrouve chez beaucoup de clients: grands comptes, PME&#8230; Il y a toujours chez eux au moins une base de données en mode de récupération FULL dont le journal n&#8217;a JAMAIS été sauvegardé. Ce n&#8217;est pas étonnant en un sens puisque FULL est le mode par défaut pour toutes les bases créées par l&#8217;utilisateur. Le résultat est un fichier LDF qui fait 80 Gb parce qu&#8217;il contient une année ou deux de transactions validées, sauvegardées dans des backup FULL depuis belle lurette, mais on le répète, en mode FULL, il n&#8217;y a qu&#8217;une sauvegarde de journal qui permet de recycler l&#8217;espace occupé par des transactions validées.</p>
<p>Reprenons notre base CRASHTEST, et créons un peu de volumétrie&#8230;</p>
<pre><span>USE</span><span> CRASHTEST</span></pre>
<pre><span>declare</span><span> @cpt int</span></pre>
<pre><span>set</span><span> @cpt=1</span></pre>
<pre><span>while</span><span>(@cpt&lt;=50000)</span></pre>
<pre><span>begin</span></pre>
<pre><span>insert</span><span> <span>into</span> TABLE1 <span>values</span> (replicate(<span>'b'</span>,5000))</span></pre>
<pre><span>set</span><span><span> </span>@cpt=@cpt+1</span></pre>
<pre><span>end</span></pre>
<pre><span>go</span></pre>
<p>&#8230;et vérifions quelle est la situation du journal à l&#8217;issue:</p>
<pre><span>DBCC</span><span> SQLPERF(LOGSPACE)</span></pre>
<pre>Database Name       Log Size (Mb)    Log Space Used (%)      Status
------------------  ---------------  ----------------------  --------
(...)               (...)            (...)                   (...)
CRASHTEST           253,3047         97,07731                0</pre>
<p>Il a plus que quadruplé de volume et il est plein.</p>
<p>Pour récupérer l&#8217;espace sur le disque, il faudra faire un DBCC SHRINKFILE en mode TRUNCATEONLY.<br />
Si je lance le DBCC SHRINKFILE tout de suite:</p>
<p><span><br />
</span></p>
<pre><span>DBCC</span><span> SHRINKFILE(’CRASHTEST_log’,<span>'TRUNCATEONLY’)</span></span></pre>
<pre>Dbid        Fileid        CurrentSize        MinimumSize    UsedPages         EstimatedPages
---------   ----------- ----------------  ---------------- ---------------   ------------------
8           2            31680            6400             31680             6400</pre>
<p>31680*8192Kb = 247,5 Mb, autant dire que presque rien n&#8217;a été fait. Celà vient du fait que le TRUNCATEONLY tronque la taille du fichier jusqu&#8217;au dernier extent alloué.<br />
Comme mon journal est plein, le dernier extent alloué est précisément à la fin du fichier.</p>
<p>Donc il faut commencer par vider ce journal: je sauvegarde ma transaction :</p>
<pre><span>backup</span><span> log CRASHTEST <span>to</span> disk=<span>'C:\CRASHTEST.log3.trn'</span> <span>with</span> init, stats, compression</span></pre>
<pre><span>go</span></pre>
<pre><span>
100 percent processed.</span></pre>
<pre><span>
Processed 31461 pages for database 'CRASHTEST', file 'CRASHTEST_log' on file 3.</span></pre>
<pre><span>
BACKUP LOG successfully processed 31461 pages in 16.391 seconds (15.723 MB/sec).</span></pre>
<p><span> </span><br />
Dans mon journal&#8230;</p>
<pre><span>DBCC</span><span> SQLPERF(LOGSPACE)</span></pre>
<pre>Database Name        Log Size (Mb)    Log Space Used (%)      Status
------------------   ---------------  ----------------------  --------
(...)                (...)            (...)                   (...)
CRASHTEST            247,4922         4,201521                 0</pre>
<p>Je retrouve mon enveloppe à 247,5Mb, et cette fois elle est bien vide. Je vais pouvoir ramener mon log à sa taille d&#8217;origine:</p>
<pre><span>DBCC</span><span> SHRINKFILE(’CRASHTEST_log’,<span>'TRUNCATEONLY’)</span></span></pre>
<p><span><br />
</span></p>
<pre>Dbid        Fileid        CurrentSize        MinimumSize    UsedPages         EstimatedPages
---------   ----------- ----------------  ---------------- ---------------   ------------------
8           2            6400               6400            6400              6400</pre>
<p>Attention, si je choisis de rester en mode FULL, je devrai programmer des sauvegardes de transactions (à travers le SQL Agent par exemple).</p>
<p>Dans le cas où ce journal fait plusieurs dizaines de Gb, je choisis de le vider en passant la base en mode SIMPLE:</p>
<pre><span lang="EN-GB">ALTER</span><span lang="EN-GB"> <span>DATABASE</span> CRASHTEST <span>SET</span> RECOVERY SIMPLE</span></pre>
<p>Un checkpoint initié dès la fin de l&#8217;ALTER se chargera de vider le contenu du journal, et il ne restera plus qu&#8217;à faire le SHRINKFILE.</p>
<p>A suivre l&#8217;effet du BULK-LOGGED sur la taille du journal&#8230;</p>
<p>[ David B. ]</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/sqldiag-episode-1/" rel="bookmark" title="5 février 2010">SQLDIAG (épisode 1)</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/journees-sql-server-a-paris-les-12-et-13-decembre-2011/" rel="bookmark" title="25 octobre 2011">Journées SQL Server à Paris les 12 et 13 décembre 2011 !</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/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/consistence-des-ecritures-avec-sata/" rel="bookmark" title="13 mars 2011">Consistence des écritures avec SATA</a> (David BAFFALEUF) [Operating SystemSQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.248 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%2Fmodes-de-recuperation-et-journal-de-transactions-episode-1%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmodes-de-recuperation-et-journal-de-transactions-episode-1%2F&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

