<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2frenchfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Cap Data Team SGBD Blog : Oracle, SQL Server, MySQL, Sybase...</title>
	
	<link>http://blog.capdata.fr</link>
	<description>Le blog technique sur les bases de données de CAP DATA Consulting</description>
	<lastBuildDate>Wed, 01 Sep 2010 13:38:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/CapDataTeamBlog" /><feedburner:info uri="capdatateamblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare href="http://add.my.yahoo.com/content?lg=fr&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/bn/intatm_fr_1.gif">Subscribe with Mon Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/CapDataTeamBlog" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsalloy.com/?rss=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.newsalloy.com/subrss3.gif">Subscribe with NewsAlloy</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://download.attensa.com/app/get_attensa.html?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.attensa.com/blogs/attensa/WindowsLiveWriter/BadgeredintoBadges_10C02/attensa_feed_button5.gif">Subscribe with Attensa for Outlook</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.flurry.com/pushRssFeed.do?r=fb&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.flurry.com/images/flurry_rss_logo2.gif">Subscribe with Flurry</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2FCapDataTeamBlog" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><feedburner:browserFriendly>Copyright © 2010  www.capdata.fr. All Rights Reserved</feedburner:browserFriendly><item>
		<title>Mythe: TORN PAGE DETECTION est moins coûteux que CHECKSUM</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/4t_LM6hw9SY/</link>
		<comments>http://blog.capdata.fr/index.php/mythe-torn-page-detection-est-moins-couteux-que-checksum/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 10:13:08 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[checksum]]></category>
		<category><![CDATA[latches]]></category>
		<category><![CDATA[page_verify]]></category>
		<category><![CDATA[torn page detection]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1742</guid>
		<description><![CDATA[C&#8217;est tentant de le penser, parce qu&#8217;on sait que le mécanisme de Torn Page Detection (TPD) ne se base que sur les premiers bits de chaque secteur de 512 octets dans chaque page, alors que le checksum calcule une somme de contrôle de toute la page. *
Sauf que pour pouvoir ajouter la signature de 2 [...]]]></description>
			<content:encoded><![CDATA[<p>C&#8217;est tentant de le penser, parce qu&#8217;on sait que le mécanisme de Torn Page Detection (TPD) ne se base que sur les premiers bits de chaque secteur de 512 octets dans chaque page, alors que le checksum calcule une somme de contrôle de toute la page. *</p>
<p>Sauf que pour pouvoir ajouter la signature de 2 bits au début de chaque secteur, SQL Server doit poser un latch exclusif sur la page (PAGELATCH_EX) alors que le checksum ne pose qu&#8217;un latch d&#8217;update (PAGELATCH_UP) , qui est plus permissif notamment avec les latches en lecture (PAGELATCH_SH). Checksum n&#8217;a pas besoin d&#8217;un latch exclusif car le résultat de la somme de contrôle va dans l&#8217;entête de la page, pas dans les données. Malin !</p>
<p>Donc utiliser des checksums provoque moins d&#8217;attente au niveau des pages dans le buffer pool que TPD.</p>
<p><em>* cf <a href="http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/">article précédent</a> pour plus de détails sur ce que font TPD et Checksums</em></p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/</div>
<p><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/sql-server-regles-dinstallation-de-base-episode-1/" rel="bookmark" title="18 juin 2009">Règles d&#8217;installation de base (épisode 1)</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
<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>
</ul>
<p><!-- Similar Posts took 30.377 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%2Fmythe-torn-page-detection-est-moins-couteux-que-checksum%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmythe-torn-page-detection-est-moins-couteux-que-checksum%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/4t_LM6hw9SY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/mythe-torn-page-detection-est-moins-couteux-que-checksum/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/mythe-torn-page-detection-est-moins-couteux-que-checksum/</feedburner:origLink></item>
		<item>
		<title>News côté formation…</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/7HPEDpKUqWw/</link>
		<comments>http://blog.capdata.fr/index.php/news-cote-formation/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 10:09:35 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[formation]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1701</guid>
		<description><![CDATA[Ça y est, Louis et moi avons terminé la nouvelle mouture de la formation SQL Server production. Les versions de SQL Server ciblées reflètent celles qui composent le parc de prod actuel et qui sont supportées par l&#8217;éditeur, c&#8217;est à dire 2005, 2008, 2008 R2.
10 sections principales sur 5 jours avec une dizaine de TP [...]]]></description>
			<content:encoded><![CDATA[<p>Ça y est, Louis et moi avons terminé la nouvelle mouture de la formation SQL Server production. Les versions de SQL Server ciblées reflètent celles qui composent le parc de prod actuel et qui sont supportées par l&#8217;éditeur, c&#8217;est à dire 2005, 2008, 2008 R2.</p>
<p>10 sections principales sur 5 jours avec une dizaine de TP pour couvrir l&#8217;essentiel de ce que doit savoir le DBA SQL Server en production. Nous avons ajouté des démos sur Resource Governor, le Change Data Capture, ainsi qu&#8217;une étude de cas de requête consommatrice. Nous travaillons actuellement sur le nouveau simulateur et les nouveaux scénarios que nous allons préparer. On mettra quelques captures d&#8217;ici quelques jours pour vous montrer à quoi ça va ressembler. Cette formation est assurée par <a href="mailto:lhochberg@capdata.fr">Louis </a>et <a href="mailto:dbaffaleuf@capdata.fr">moi-même</a> en intra et en inter-entreprise. Vous pouvez nous contacter pour les détails techniques.</p>
<p>Pour les infos commerciales, planning, tarifs, etc&#8230; vous pouvez contacter la hotline commerciale au <em><strong>0820 620 400</strong></em> ou télécharger la plaquette <a href="http://www.capdata.fr/formation-sql-server.htm">ici</a>.</p>
<p>Le découpage plan / jour sera le suivant:</p>
<h2><strong>Partie I: Architecture et généralités (Jour1)<br />
</strong></h2>
<p>Pour ceux qui utilisent déjà SQL Server ce sera une révision, et pour les non-initiés une découverte du produit. La première partie permet une remise à plat des connaissances nécessaires pour aller plus loin dans le cours.</p>
<h3><em><strong>I.1 Généralités:</strong></em></h3>
<p>- Description du package: différents outils (SSRS, SSIS, SSBIS, SSAS, etc&#8230;), des différents SKU (Enterprise, Standard, Express, etc&#8230;).<br />
- Quelques rappels sur les notions de base: tables, vues, procédures stockées, triggers, curseurs, etc&#8230;<br />
- Rappels sur les indexes: indexes cluster, non cluster, vues indexées, &#8230;<br />
- Rappels sur la concurrence d&#8217;accès: mode d&#8217;isolation et verrouillage.</p>
<h3><em><strong>I.2: Architecture SQL Server:</strong></em></h3>
<p>- Processus, zones mémoire, bases systèmes, fichier ERRORLOG, connectivité, stockage, &#8230;</p>
<h3><em><strong>I.3: Architecture d&#8217;une base de données: </strong></em></h3>
<p>- Fichiers de données, groupes de fichiers, allocation, IN-ROW, OFF-ROW, LOB&#8230;.<br />
- Journal de transactions.<br />
- Options de bases de données, création, modification, suppression&#8230;.</p>
<h2><strong>Partie II: Bonnes pratiques d&#8217;installation.(Jour1)<br />
</strong></h2>
<p>Plutôt que de livrer un pas à pas tout bête, nous avons essayé de mettre en avant la préparation qui est à la base de tout succès.<br />
<strong>- </strong>Discussion autour du thème machine virtuelle / physique, question des licences, définition et préparation des axes, comptes de services, collation, mode d&#8217;authentification, dimensionnement des bases&#8230;<br />
- Installation automatisée et pas à pas, maintenance: changement d&#8217;option, arrêt démarrage, DAC&#8230;<br />
<span style="color: #0000ff;">-&gt; TP.</span></p>
<h2><strong>Partie III: Maintien en conditions opérationnelles (Jour2 / Jour3)<br />
</strong></h2>
<p>C&#8217;est le cœur de la formation. On va passer en revue les tâches que le DBA doit mettre en place, et comment il peut les automatiser.</p>
<h3><em><strong>III.1: Backups / Restaurations: </strong></em></h3>
<p>- Modes de récupération des transactions, mediasets&#8230;<br />
- Différents types de backups: complet, de journal de transaction, tail-log, différentiel.<br />
- Différents types de restaurations: après un crash, sur une base différente, restauration de pages.<br />
- Vérification des sauvegardes.<br />
- Impact du Bulk Logged.<br />
<span style="color: #0000ff;">-&gt; TP.</span></p>
<h3><em><strong>III.2: Contrôles de cohérence (DBCC CHECKDB):</strong></em></h3>
<p>- Pourquoi effectuer des contrôles de cohérence.<br />
- Comment interpréter les résultats.<em><strong><br />
- </strong></em>Quoi faire<em><strong> </strong></em>en cas d&#8217;erreurs remontées par DBCC CHECKDB.</p>
<h3><em><strong>III.3: Fragmentation</strong></em></h3>
<p><em><strong> </strong></em>- Origines de la fragmentation logique, impact sur les performances.<br />
- Reconstruction des indexes.<em><strong><br />
</strong></em></p>
<h3><em><strong>III.4: Collecte des statistiques</strong></em></h3>
<p>- Contenu des statistiques.<br />
- Collecte automatique vs collecte manuelle.<em><strong> </strong></em><em><strong> </strong></em></p>
<h3><em><strong>III.5: Gestion de la volumétrie:</strong></em></h3>
<p><em><strong> </strong></em>- SHRINK sur les fichiers de données<em><strong> </strong></em>/ journaux<em><strong><br />
</strong></em>- Conseils sur la réduction de fichiers.<br />
<span style="color: #0000ff;">-&gt; TP.</span></p>
<h3><strong>III.6: Automatisation des tâches de maintenance .</strong></h3>
<p>- SQL Agent, plans de maintenance.<br />
- Notification via Database Mail.<br />
- Gestion des alertes.<br />
- Collecter les données (Data Collector).<br />
<span style="color: #0000ff;">-&gt; TP</span></p>
<h2><strong>Partie IV: Demandes de travaux: (Jour3)<br />
</strong></h2>
<p>- Import / export de données (BCP, BULK INSERT, SSIS) <span style="color: #0000ff;">-&gt; TP</span><br />
-  Détacher /rattacher une base <span style="color: #0000ff;">-&gt; TP</span><br />
- Database snapshot <span style="color: #0000ff;">-&gt; TP</span><br />
- Serveurs liés.</p>
<h2>Partie V: Outils d&#8217;administration: (Jour4)</h2>
<p>- SQLCMD<br />
- DAC<br />
- Resource Governor <span style="color: #0000ff;">-&gt; DEMO</span></p>
<h2>Partie V: Sécurité: (Jour4)</h2>
<p>- Définition des risques.<br />
- Accès, authentification, et ACLs <span style="color: #0000ff;">-&gt; TP</span><br />
- Chiffrement, protection des données.<br />
- Techniques d&#8217;audit: Policies, trace par défaut, rapports  SSMS, audit C2, Change Data Capture <span style="color: #0000ff;">-&gt; DEMO</span></p>
<h2>Partie VI: Cas de corruptions de données (Jour4)<em><strong> </strong></em></h2>
<p><em><strong>- </strong></em>Importance des sauvegardes, outils, recovery, etc&#8230;<br />
- Cas de corruption sur une base système en SQL Server 2005/2008.<br />
- Problème de recovery sur une base système en SQL Server 2005/2008.<br />
- Problème sur un fichier de données de base utilisateur.<br />
- Problème de recovery sur une base utilisateur.<br />
<span style="color: #0000ff;">-&gt; TP</span></p>
<h2>Partie VII: VLDB (Very Large Data Bases): (Jour4)</h2>
<p>- Définition de la problématique des VLDB.<br />
- Stockage des données étendues (OFF-ROW, LOB, FILESTREAM)<br />
- Compression des données (page, ligne, colonnes sparse).<br />
- Techniques de backup par groupes de fichiers.<br />
- Partitionnement de tables.<br />
- Glissement de partitions.</p>
<h2>Partie VIII: Problématiques de migration (Jour4)</h2>
<p>- Cycles de vie de SQL Server.<br />
- Obsolescence des fonctionnalités.<br />
- SQL Upgrade Advisor.<br />
- Méthodologies de migration.<br />
- Le problème DTS.</p>
<h2>Partie IX: Performances: (Jour5)</h2>
<h3><em><strong>IX.1: Utilisation des ressources par SQL Server:</strong></em></h3>
<p>- CPU: SQLOS, planification, paramètres appliqués à la CPU (max worker threads, affinités, priorité, etc&#8230;)<br />
- Mémoire: 32 bits et 64 bits, AWE, page verrouillées en mémoire, Buffer POOL, PLAN CACHE,  etc&#8230;<br />
- Disques: Scatter/Gather IOs, IO asynchrones, IO non bufferisées.<br />
- Tempdb.<br />
- Les antivirus et les bases de données.</p>
<h3><em><strong>IX.2: Optimisation des requêtes:</strong></em></h3>
<p>- Le pipeline de la compilation.<br />
- Phases d&#8217;optimisation prises en charge par l&#8217;optimiseur.<br />
- Recompilations.<br />
- Lecture d&#8217;un plan d&#8217;exécution et principaux opérateurs.<br />
- Types de jointures (NLJ, MJ, HJ)<br />
- Couverture d&#8217;une requête.<br />
- Etude de cas <span style="color: #0000ff;">-&gt; DEMO</span></p>
<h3><em><strong>IX.3: Les outils de mesure:</strong></em></h3>
<p>- Vues basiques de SSMS.<br />
- Outils Windows: TM, Perfmon, ETW, etc&#8230;<br />
- Compteurs perfmon types pour windows et SQL Server;<br />
- SQL Trace et profiler <span style="color: #0000ff;">-&gt; TP</span><br />
- DTA.<br />
- DMVs.<br />
- Outils divers: SQLDIAG, SQL Nexus, RML Utilities, Performance Dashboard SQL 2005, rapports SSMS.<br />
- Extended events (XE).<br />
- set statistics &#8230;</p>
<h3><em><strong>IX.4: Démarche de résolution d&#8217;un problème:</strong></em></h3>
<p>- Analyse du problème à chaud (mode &#8216;pompier&#8217;): outils, techniques et astuces&#8230;<br />
- Analyse du problème à postériori avec et sans traces.</p>
<h2>Partie X: Haute disponibilité et réplication: (Jour5)</h2>
<h3><em><strong>X.1: Cluster SQL Server.</strong></em></h3>
<p>- Notions de cluster simple-instance / multi-instance.<br />
- Problèmes liés aux clusters.</p>
<h3><em><strong>X.2: Log Shipping:</strong></em></h3>
<p>- Mise en place du log shipping.<br />
- Problèmes liés au log shipping.</p>
<h3><em><strong>X.3: Database Mirroring:</strong></em></h3>
<p>- Différentes topologies.<br />
- Mise en place du DB mirroring.<br />
- Problèmes liés au Database Mirroring.<br />
<span style="color: #0000ff;">-&gt; TP</span></p>
<h3><em><strong>X.4: Réplication:</strong></em></h3>
<p>- Topologies de réplication.<br />
- Différents acteurs de la réplication transactionnelle.<br />
- Maintenance de la réplication.<br />
- Problèmes liés à la réplication.<br />
<span style="color: #0000ff;">-&gt; TP</span></p>
<p>- Comparatif des différentes solutions de HA.</p>
<h2>Partie XI: Q&amp;A</h2>
<p>A suivre la formation spéciale optimisation de requêtes. A+</p>
<p>David B.<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">None Found
</ul>
<p><!-- Similar Posts took 52.773 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%2Fnews-cote-formation%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fnews-cote-formation%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/7HPEDpKUqWw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/news-cote-formation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/news-cote-formation/</feedburner:origLink></item>
		<item>
		<title>Saines lectures</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/jMTWcMaz8m0/</link>
		<comments>http://blog.capdata.fr/index.php/saines-lectures/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 16:13:42 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[livres]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1645</guid>
		<description><![CDATA[Une autre question fréquemment posée en formation et d&#8217;ordre plus général concerne les lectures conseillées sur SQL Server et les sujets associés. La liste qui suit n&#8217;engage bien évidemment que moi.
Les bouquins
En général les stagiaires rechignent toujours autant à se mettre à l&#8217;anglais, et c&#8217;est bien dommage car la plupart du temps la doc est [...]]]></description>
			<content:encoded><![CDATA[<p>Une autre question fréquemment posée en formation et d&#8217;ordre plus général concerne les lectures conseillées sur SQL Server et les sujets associés. La liste qui suit n&#8217;engage bien évidemment que moi.</p>
<h2>Les bouquins</h2>
<p>En général les stagiaires rechignent toujours autant à se mettre à l&#8217;anglais, et c&#8217;est bien dommage car la plupart du temps la doc est en anglais et n&#8217;est souvent pas traduite du tout. Pour les bouquins en français sur SQL Server je ne saurais que trop recommander de lire des livres écrits par des français car les traductions sont parfois hasardeuses. Personnellement je ne connais que celui de <a href="http://www.babaluga.com/doku.php/livres">Rudi Bruchez</a>, c&#8217;est le seul qui rentre un peu dans les détails.</p>
<p>Mon exemplaire de <a href="http://www.amazon.com/Gurus-Guide-Server-Architecture-Internals/dp/0201700476/ref=sr_1_4?ie=UTF8&amp;s=books&amp;qid=1282685086&amp;sr=8-4">Guru&#8217;s Guide for SQL Server Architecture and Internals</a> de <a href="http://blogs.msdn.com/b/khen1234/">Ken Henderson</a> est tellement noirci de notes et de commentaires qu&#8217;il n&#8217;est presque plus lisible. A chaque relecture je suis soufflé par le niveau de détail et la qualité des exemples qu&#8217;il apporte pour démontrer la façon dont le moteur est construit. Jusqu&#8217;ici, personne n&#8217;a réussi à arriver au quart du dixième de la cheville de ce qu&#8217;il montre. Toute personne désirant vraiment plonger dans le moteur devrait l&#8217;avoir sur son bureau.</p>
<p><a href="http://www.amazon.com/SQL-Server-2005-Practical-Troubleshooting/dp/0321447743/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1282685808&amp;sr=8-1">SQL Server 2005 Practical Troubleshooting Guide</a> a été rédigé sous la baguette de mister Henderson encore lui, par des membres de l&#8217;équipe de développement de SQL Server (Slava Oks, Santeri Voutilainen, Sameer Teijani, Cesar Galindo-Legaria,  etc&#8230;) ainsi que des membres du support (Bob Ward, Bart Duncan, Cindy Gross). Chacun parle de son domaine d&#8217;expertise, Santeri de la partie Waits, Slava de SQLOS et de la gestion de la mémoire, Sameer du scheduling, Cindy Gross du cluster, et Bob Ward nous livre deux chapitres magistraux sur le débogage, la lecture de minidumps, des tonnes d&#8217;informations qu&#8217;on ne trouve nulle part ailleurs sur le net. Là encore un must-read pour tous ceux qui souhaitent approfondir le sujet.</p>
<p><a href="http://www.amazon.com/Microsoft-SQL-Server-2008-Internals/dp/0735626243/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1282686460&amp;sr=1-1">SQL Server 2008 Internals</a>: Le dernier en date vraiment intéressant, rédigé par les stars du moment (Randal / Tripp / Delaney / Machanic / Cunningham). Là encore, chaque personne parle de ce qu&#8217;il connaît le mieux, Kim Tripp des indexes, Paul Randal de DBCC CHECKDB,  Conor Cunningham de l&#8217;optimiseur et Adam Machanic de la partie tracing. Kalen Delaney se charge d&#8217;envoyer tout le reste comme à son habitude avec une extrême clarté. C&#8217;est le moins profond des trois, mais on se fait quand même des bonnes migraines.</p>
<p>Au delà de ces trois là, je ne vois pas ce qu&#8217;il pourrait y avoir d&#8217;autre à raconter sur le moteur. Peut être les livres d&#8217;<a href="http://www.amazon.com/Server-Failover-Clustering-Experts-Voice/dp/1430219661/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1282686713&amp;sr=1-1">Allan Hirt</a> sur le cluster SQL Server, d&#8217;<a href="http://www.amazon.com/Inside-Microsoft-SQL-Server-2008/dp/0735626030/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1282686848&amp;sr=1-1">Itzik Ben-Gan</a> sur Transact-SQL et celui d&#8217;<a href="http://www.amazon.com/exec/obidos/ASIN/0974973602/wwwwhitebearc-20/103-2661713-9431811?_encoding=UTF8&amp;camp=1789&amp;link_code=xm2">Hillary Cotter</a> sur la réplication, il faudrait qu&#8217;il en réécrive un sur la version 2008 un jour.</p>
<p>Je n&#8217;ai pas encore lu le <a href="http://www.amazon.com/Professional-Server-2008-Internals-Troubleshooting/dp/0470484284/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1282687233&amp;sr=8-1">bouquin </a>auquel ont participé John Kehayias, James Rowland Jones et Brent Ozar, si quelqu&#8217;un veut donner son avis dans les commentaires.</p>
<h2>Les blogs:</h2>
<p>Le problème des blogs, c&#8217;est qu&#8217;il y en a tellement qu&#8217;on ne peut pas tous les suivre, et que les plus intéressants sont aussi souvent les plus actifs.</p>
<p><strong>Les blogs en français:</strong></p>
<p>- <a href="http://blog.developpez.com/mikedavem/">Mikedavem</a>.<br />
- <a href="http://blog.developpez.com/sqlpro/">Frédéric Brouard</a>.<br />
- <a href="http://blogs.developpeur.org/christian/">Christian Robert</a>.<br />
- <a href="http://www.babaluga.org/blog/">Rudi Bruchez</a>.<br />
- <a href="http://www.sqlpac.com/">SQLPac</a>.</p>
<p><strong>Les blogs US:</strong></p>
<p>- <a href="http://blogs.msdn.com/b/psssql/">PSS</a>.<br />
- <a href="http://blogs.msdn.com/b/sqlblog/">SQL Server Support Team</a>.<br />
- <a href="http://blogs.msdn.com/b/sqlserverstorageengine/">SQL Server Storage Engine Team</a><br />
- <a href="http://blogs.msdn.com/b/sqlqueryprocessing/">SQL Server Relationnal Engine team</a>.<br />
- <a href="http://blogs.msdn.com/b/sqlclr/">SQLCLR Support team</a>.<br />
- <a href="http://blogs.msdn.com/b/mwories/">Micheal Wories</a> (SQLPS)<br />
- <a href="http://www.sqlskills.com/blogs.asp">SQLSKILLS</a>.<br />
- <a href="http://blogs.msdn.com/b/craigfr/">Craig Freedman.</a><br />
- <a href="http://www.sqlskills.com/BLOGS/PAUL/post/Wow-so-many-blogs!.aspx">Liste étendue</a>.</p>
<h2>Sur Windows:</h2>
<p><a href="http://www.amazon.com/Windows%C2%AE-Internals-Including-Windows-PRO-Developer/dp/0735625301/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1282745564&amp;sr=8-1">- Windows Internals, 5th edition</a>, de Mark Russinovich et Dave Solomon.<br />
- Le blog de <a href="http://blogs.technet.com/b/markrussinovich/">Mark Russinovich</a>.</p>
<h2>Les videos:</h2>
<p><strong>- Les interviews des développeurs et architectes  Windows sur Channel 9:</strong><br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Windows-Part-I-Dave-Probert/">Dave Probert.</a> (Kernel)<br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Arun-Kishan-Farewell-to-the-Windows-Kernel-Dispatcher-Lock/">Arun Kishan</a>. (Scheduling &amp; Dispatcher lock)<br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Neal-Christiansen-Inside-File-System-Filter-part-I/">Neal Christiansen</a> (Filter Driver Manager)<br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Windows-NT-Cache-Manager-Molly-Brown/">Molly Brown</a>. (Cache Manager)<br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Nar-Ganapathy-Windows-the-IO-Manager-and-Driver-Model--Part-I/">Nar Ganapathy</a>.  (IO Manager)<br />
- <a href="http://channel9.msdn.com/shows/Going%20Deep/Mark-Russinovich-Inside-Windows-7/">Mark Russinovich</a>. (Windows 7 kernel)<br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Rob-Short-and-kernel-team-Going-deep-inside-Windows-Vistas-kernel-architecture/">Rob Short</a>. (Vista Kernel)<br />
- <a href="http://channel9.msdn.com/shows/Going+Deep/Landy-Wang-Windows-Memory-Manager/">Landy Wang</a>. (Memory Manager)</p>
<p><strong>- Videos sur SQL Server :</strong><br />
- Interview de <a href="http://channel9.msdn.com/shows/Going+Deep/Dave-Campbell-Inside-SQL-Services/">Dave Campbell</a> sur Channel9 (SQL Azure).<br />
- Interview de <a href="http://channel9.msdn.com/posts/TheChannel9Team/Jim-Gray-A-talk-with-THE-SQL-Guru-and-Architect/">Jim Gray</a> en 2005.<br />
- Euan Garden fait la visite des bureaux du building  35  -  Part <a href="http://channel9.msdn.com/posts/TheChannel9Team/Euan-Garden-Tour-of-SQL-Server-Team-part-I/">I</a> &#8211; <a href="http://channel9.msdn.com/posts/TheChannel9Team/Euan-Garden-Tour-of-SQL-Server-Team-Part-II/">II</a> -<a href="http://channel9.msdn.com/posts/TheChannel9Team/Euan-Garden-Tour-of-SQL-Server-Team-Part-III/"> III</a> -<a href="http://channel9.msdn.com/posts/TheChannel9Team/Euan-Garden-Tour-of-SQL-Server-team-Part-IV/">IV</a>.<br />
- <a href="https://channel9.msdn.com/posts/TheChannel9Team/Euan-Garden-If-someone-wants-to-work-on-the-SQL-Server-team-what-is-involved/">Engagez-vous</a> qu&#8217;y disaient.</p>
<p>Il existait aussi une tonne de vidéos de la TechEd 2008 sur Spotlight malheureusement elles ont toutes été retirées.</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/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/" rel="bookmark" title="30 mars 2010">Un trigger fait-il parti d&#8217;une transaction ?</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<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/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 25.523 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%2Fsaines-lectures%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsaines-lectures%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/jMTWcMaz8m0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/saines-lectures/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/saines-lectures/</feedburner:origLink></item>
		<item>
		<title>Fragmentation sur des tables stockées en S-GAM</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/xotAjfPhhHQ/</link>
		<comments>http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 18:07:21 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[dbcc ind]]></category>
		<category><![CDATA[dbcc showcontig]]></category>
		<category><![CDATA[fragmentation]]></category>
		<category><![CDATA[SGAM]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1065</guid>
		<description><![CDATA[C&#8217;est une question que j&#8217;ai fréquemment eu en formation à la suite d&#8217;un TP sur la fragmentation des indexes.
Soit une table &#8216;FILLIALE&#8216; avec la définition suivante:
FILLIALE {
        [ID_FILLIALE] [int] NOT NULL,
	[RAISOC] [varchar](50) NULL,
	[ADRESSE] [varchar](100) NULL,
	[CODEPOSTAL] [char](5) NULL,
	[VILLE] [varchar](50) NULL,
	[ID_GERANT] [int] NULL
}

Elle contient 240 lignes, une clé primaire PK_FILLIALE [...]]]></description>
			<content:encoded><![CDATA[<p>C&#8217;est une question que j&#8217;ai fréquemment eu en formation à la suite d&#8217;un TP sur la fragmentation des indexes.</p>
<p>Soit une table &#8216;<em>FILLIALE</em>&#8216; avec la définition suivante:</p>
<pre><span style="color: #008000;">FILLIALE {
        [ID_FILLIALE] [int] NOT NULL,
	[RAISOC] [varchar](50) NULL,
	[ADRESSE] [varchar](100) NULL,
	[CODEPOSTAL] [char](5) NULL,
	[VILLE] [varchar](50) NULL,
	[ID_GERANT] [int] NULL
}
</span></pre>
<p>Elle contient 240 lignes, une clé primaire PK_FILLIALE sur ID_FILLIALE. La mesure du taux de fragmentation de l&#8217;index cluster remonte <strong>66,666666..7 %</strong> . L&#8217;intitulé du TP indique d&#8217;utiliser ALTER INDEX REBUILD pour la fragmentation  supérieure à 30%, ce serait donc le cas ici. Sauf qu&#8217;un ALTER INDEX REBUILD ne change rien à cette valeur:</p>
<pre><span style="color: #0000ff;">select I.name, F.avg_fragmentation_in_percent from sys.indexes I
cross apply sys.dm_db_index_physical_stats(db_id(),object_id('FILLIALE'),
-1,NULL,DEFAULT) F
where I.object_id = object_id('FILLIALE')</span>

<em><span style="color: #3366ff;">name            avg_fragmentation_in_percent
--------------  ----------------------------
PK_FILLIALE     66,6666666666667</span></em>

<span style="color: #0000ff;">ALTER INDEX PK_FILLIALE ON FILLIALE REBUILD
GO</span>

<span style="color: #0000ff;">select I.name, F.avg_fragmentation_in_percent from sys.indexes I
cross apply sys.dm_db_index_physical_stats(db_id(),object_id('FILLIALE'),
-1,NULL,DEFAULT) F
where I.object_id = object_id('FILLIALE')</span>
<em><strong>
</strong><span style="color: #3366ff;">name            avg_fragmentation_in_percent
--------------  ----------------------------
PK_FILLIALE     66,6666666666667</span></em></pre>
<p>D&#8217;où la question du stagiaire: &#8220;mais pourquoi si je lance 20 fois la reconstruction de l&#8217;index, la table est toujours fragmentée à 66,6% ?&#8221;</p>
<h3>Représentation physique de la table FILLIALE:</h3>
<p>Petite piqûre de rappel sur le stockage: les données sont stockées dans des pages de 8192 octets, elles mêmes regroupées dans des groupes de 8 pages que l&#8217;on appelle <em>extents (on voit aussi </em><em>allocation_units </em>ou <em>fragments</em>). Deux types d&#8217;extents coexistent dans un fichier de données:</p>
<ul>
<li><strong>Les extents &#8216;uniformes&#8217;:</strong> sont alloués pour les tables dont l&#8217;allocation dépasse 8 pages, donc 64+Kb. Ces pages sont gérées dans un plan d&#8217;allocation standard qu&#8217;on appelle GAM (pour Global Allocation Map).</li>
<li><strong>Les extents &#8216;mixtes&#8217;:</strong> sont alloués pour les tables dont l&#8217;allocation initiale est inférieure à 8 pages. Ces pages sont gérées dans un plan d&#8217;allocation spécial qu&#8217;on appelle S-GAM (pour Short-GAM ou Shared-GAM comme on veut, personne n&#8217;a jamais compris ce que S voulait vraiment dire, et chacun a sa version).</li>
</ul>
<p>Si  on regarde de quelle manière est stockée notre table FILLIALE:</p>
<pre><span style="color: #0000ff;">select I.name, F.index_id, F.index_depth, F.index_level, F.avg_fragmentation_in_percent,
F.fragment_count, F.avg_fragment_size_in_pages, F.page_count, record_count
from sys.indexes I
cross apply sys.dm_db_index_physical_stats(db_id(),object_id('FILLIALE'),-1,NULL,'DETAILED') F
where I.object_id = object_id('FILLIALE')</span>
<em>
<span style="color: #3366ff;">name          index_id    index_depth index_level avg_fragmentation_in_percent fragment_count       (...)
------------- ----------- ----------- ----------- ---------------------------- --------------------
PK_FILLIALE   1           2           0           66,6666666666667             3
PK_FILLIALE   1           2           1           0                            1                    

(...) avg_fragment_size_in_pages page_count           record_count
     -------------------------- -------------------- --------------------
     1                          3                    240
     1                          1                    3</span></em></pre>
<p>On voit qu&#8217;elle est composée de 4 pages: une page avec un index_level à 1 qui désigne la root page de l&#8217;index cluster. Elle contient 3 lignes (record_count=3) parce qu&#8217;elle pointe vers chacune des pages du niveau inférieur. En dessous (index_level=0), il y a 3 pages qui constituent le niveau feuille de l&#8217;index cluster, donc les données. Elles contiennent les 240 lignes de notre table.</p>
<p>Si FILLIALE est composée de 4 pages de données + index, alors elle tombe invariablement dans la catégorie S-GAM. Les valeurs de <em>fragment_count</em> et <em>avg_fragment_size_in_pages</em> sur la première ligne nous le montrent: 3 pages dans trois fragments (on rappelle fragment = extent), donc chacune dans le sien. Histoire de bien se représenter visuellement la façon dont la table est stockée, on peut utiliser un dbcc ind:</p>
<pre><span style="color: #0000ff;">dbcc ind('CAPDATA','FILLIALE',-1)</span>

<em><span style="color: #3366ff;">PageFID PagePID     IAMFID IAMPID      ObjectID    IndexID     PartitionNumber PartitionID          (...)
------- ----------- ------ ----------- ----------- ----------- --------------- --------------------
<span style="color: #999999;">1       79          NULL   NULL        1189579276  1           1               72057594040221696    </span>
1       127         1      79          1189579276  1           1               72057594040221696
1       94          1      79          1189579276  1           1               72057594040221696
<span style="color: #ff0000;">1       256         1      79          1189579276  1           1               72057594040221696    </span>
1       257         1      79          1189579276  1           1               72057594040221696    

(...) iam_chain_type       PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
      -------------------- -------- ---------- ----------- ----------- ----------- -----------
  <span style="color: #999999;">    In-row data          10       NULL       0           0           0           0</span>
      In-row data          1        0          1           94          0           0
      In-row data          1        0          1           257         1           127
   <span style="color: #ff0000;">   In-row data          2        1          0           0           0           0</span>
      In-row data          1        0          0           0           1           94</span></em></pre>
<p>La page 1:79 est la page d&#8217;allocation de l&#8217;objet, on n&#8217;en parle donc pas. Pour le reste, on voit que la page 1:256 est la page racine de notre index (index_level=1), et pointe dans l&#8217;ordre vers 1:127 -&gt; 1:94 -&gt; 1:257 comme suit:</p>
<pre><strong><span style="color: #008000;">	/  |1:127|
	     |
<span style="color: #0000ff;">|1:256| </span>-- <span style="color: #ff0000;">|1:94|</span>
	     |
	\  <span style="color: #0000ff;">|1:257|</span></span></strong></pre>
<p>En couleurs les 3 extents où se trouvent physiquement les pages: 1:94 dans un extent, 1:127 dans un autre, et 1:256 / 1:257 dans un troisième (elles se suivent et 1:256 est la première page du 33ième extent dans le fichier).</p>
<h3>Calcul de la fragmentation:</h3>
<p>Calculer la fragmentation d&#8217;un index revient à calculer le rapport entre le nombre de fragments qu&#8217;on <strong>a dû lire </strong>pour récupérer toutes les pages et le nombre de fragments qu&#8217;on <strong>aurait dû </strong>lire dans le cas idéal. Si on prend une table de 1680 pages, le cas idéal est celui où on ne lit que (1680/8)=210 fragments. Si les 1680 pages se trouvent sur plus de 210 fragments, alors on s&#8217;éloigne du 100% de densité et on augmente la valeur de la fragmentation.</p>
<p>Si je reprends le cas de la table FILLIALE, le cas idéal aurait été (3/8) ~= 1  fragment à lire seulement, or on doit en lire toujours 3. Cette information est visible dans <strong>DBCC SHOWCONTIG</strong>:</p>
<pre><span style="color: #0000ff;">dbcc showcontig('FILLIALE','PK_FILLIALE')</span>

<em><span style="color: #3366ff;">DBCC SHOWCONTIG analyse la table 'FILLIALE'...
Table : 'FILLIALE' (1189579276) ; index ID : 1, base de données ID : 5
Analyse du niveau TABLE effectuée.
- Pages analysées................................: 3
- Extensions analysées..............................: 3
- Commutateurs d'extension..............................: 2
- Moyenne des pages par extension........................: 1.0
<strong><span style="color: #ff0000;">- Densité d'analyse [meilleure valeur:valeur réelle].......: 33.33% [1:3]</span></strong>
- Fragmentation d'analyse logique..................: 66.67%
- Fragmentation d'analyse d'extension...................: 66.67%
- Moyenne d'octets libres par page.....................: 1877.0
- Densité de page moyenne (complète).....................: 76.81%
Exécution de DBCC terminée. Si DBCC vous a adressé des messages d'erreur, contactez l'administrateur système.</span></em></pre>
<p><span style="color: #ff6600;"><strong>[1:3] </strong></span>signifie qu&#8217;on aurait dû ne lire qu&#8217;un seul fragment, or on a en lu 3 (<em>extensions analysées = 3</em>), parce qu&#8217;on est sur une table où les pages sont dans trois extents. Donc 100-33.33333&#8230; = 66.6666&#8230;7%</p>
<p>Dommage que SHOWCONTIG doive disparaître à terme, l&#8217;affichage me paraissait plus lisible que la DMV qui le remplace. Qui me suit pour une pétition ??</p>
<p>A+ David B.</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">﻿</div>
<p><script src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO" type="text/javascript"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/saines-lectures/" rel="bookmark" title="25 août 2010">Saines lectures</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/" rel="bookmark" title="30 mars 2010">Un trigger fait-il parti d&#8217;une transaction ?</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/" rel="bookmark" title="6 avril 2010">Modifier PAGE_VERIFY après une migration depuis SQL 2000</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 48.542 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%2Ffragmentation-sur-des-tables-stockees-en-s-gam%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Ffragmentation-sur-des-tables-stockees-en-s-gam%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/xotAjfPhhHQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/</feedburner:origLink></item>
		<item>
		<title>Une alternative à xp_fixeddrives</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/JgaEXpqk9rQ/</link>
		<comments>http://blog.capdata.fr/index.php/une-alternative-a-xp_fixeddrives/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 08:35:29 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[sqlclr]]></category>
		<category><![CDATA[xp_fixeddrives]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1519</guid>
		<description><![CDATA[Pour faire simple, le besoin est de pouvoir récupérer l&#8217;équivalent d&#8217;un df (UNIX) en Transact-SQL, c&#8217;est à dire ça:
$ df -k
Sys. de fich.        1K-blocs       Occupé     Disponible  Capacité     Monté sur
c:                    40957684     28061160    12896524    69%       [...]]]></description>
			<content:encoded><![CDATA[<p>Pour faire simple, le besoin est de pouvoir récupérer l&#8217;équivalent d&#8217;un <strong>df </strong>(UNIX) en Transact-SQL, c&#8217;est à dire ça:</p>
<pre><span style="color: #0000ff;">$ df -k
Sys. de fich.        1K-blocs       Occupé     Disponible  Capacité     Monté sur
c:                    40957684     28061160    12896524    69%         /cygdrive/c
e:                   210170360     133011444   77158916    64%         /cygdrive/e
g:                    78153152     19149152    59004000    25%         /cygdrive/g
v:                    61440576     30980608    30459968    51%         /cygdrive/v</span></pre>
<p>Il existe dans SQL Server une procédure stockée étendue<em> xp_fixeddrives</em> qui renvoie une approximation table-valuée du df, mais il y manque des informations importantes comme par exemple la taille du drive:</p>
<pre><span style="color: #0000ff;">exec xp_fixeddrives

drive   Mo disponibles
-----   --------------
C	12594
E	75350
G	57621
V	29746</span></pre>
<p>Il nous fallait donc réécrire notre propre <em>xp_fixeddrives </em>en le formattant comme un <strong>df</strong> (sans l&#8217;information du point de montage), sous la forme d&#8217;une fonction table valuée en SQLCLR *.</p>
<h3><strong>Le source de <em>fn_fixeddrives.dll</em>: </strong><strong><br />
</strong></h3>
<p>On récupère les propriétés des lecteurs assez simplement en utilisant la méthode <em>GetDrives()</em> de la classe <em>DriveInfo</em>, et on stocke le résultat dans un tableau, que l&#8217;on affiche ensuite ligne à ligne.</p>
<pre><span style="color: #008000;">using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Collections;

<span style="color: #0000ff;">public partial class cFixedDrives
{
    static DriveInfo[] _t_drvlist;

    [Microsoft.SqlServer.Server.SqlFunction
        (
            FillRowMethodName = "<span style="color: #008000;">_f_fill</span>",
            TableDefinition = "<span style="color: #008000;">Drive nvarchar(3), SizeMb bigint, UsedMb bigint, "<span style="color: #0000ff;">+</span>
            "AvailableMb bigint, UsePct bigint</span>"
        )
    ]

  <span style="color: #008000;">  // Main</span>
    public static IEnumerable fn_fixeddrives()
    {
        _t_drvlist = DriveInfo.GetDrives();
        ArrayList _t_index = new ArrayList();
        int i = 0;

        foreach (DriveInfo _drv in _t_drvlist)
        {
            if (("<span style="color: #008000;">Fixed</span>" == _drv.DriveType.ToString()) &amp;&amp; (_drv.IsReady))
            {
                _t_index.Add(i);
            }
            i++;
        }

        return _t_index;
    }

<span style="color: #008000;">    // _fill</span>
    private static void _f_fill(Object _v_Obj, out string _v_drvName,
                                out long _v_totalsizeMb, out long _v_usedsizeMb,
                                out long _v_freesizeMb, out long _v_pctused)
    {
        int _t_row = (int)_v_Obj;

        _v_drvName = _t_drvlist[_t_row].Name;
        _v_totalsizeMb = _t_drvlist[_t_row].TotalSize / 1048576;
        _v_usedsizeMb = (_t_drvlist[_t_row].TotalSize - _t_drvlist[_t_row].TotalFreeSpace)
                          / 1048576;
        _v_freesizeMb = _t_drvlist[_t_row].TotalFreeSpace / 1048576;
        _v_pctused = ((_t_drvlist[_t_row].TotalSize - _t_drvlist[_t_row].TotalFreeSpace)
                        * 100 / _t_drvlist[_t_row].TotalSize);
    }
};</span></span></pre>
<p>Globalement, pour qu&#8217;une fonction SQLCLR puisse retourner une table, elle doit renvoyer un type <em>IEnumerable. </em>L&#8217;élément important est dans le rôle de la fonction de traitement des lignes (<em> _f_fill()</em> ). Cette fonction va être appelée de manière itérative par la fonction principale <em>fn_fixeddrives()</em> à chaque fois qu&#8217;une ligne du tableau est fetchée, un peu comme dans un curseur, et va traiter et retourner la valeur de chaque colonne de la ligne. A la fin de l&#8217;itération, on obtient une table.</p>
<p>La seule vague astuce consiste à stocker dans un <em>Arraylist </em>les positions dans le <em>DriveInfo[]</em> où les lecteurs sont de type &#8216;<em>Fixed</em>&#8216;, car les propriétés de taille ou d&#8217;espace libre ne sont pas renvoyées pour les autres types de lecteurs (par exemple les lecteurs de DVD), et plutôt que de passer à <em>_f_fill()</em> le tableau <em>DriveInfo[]</em> contenant la liste des drives, on passe juste un petit tableau d&#8217;entiers contenant les positions des disques fixes, et on s&#8217;en sert comme d&#8217;un index pour affecter les colonnes en retour. On utilise un <em>ArrayList </em>à la place d&#8217;un <em>int[] </em>parce qu&#8217;on ne sait pas au départ combien de lecteurs fixes on aura sur la machine.</p>
<p>A noter le test <span style="color: #0000ff;">&amp;&amp; (_drv.IsReady)</span> qui permet d&#8217;éviter de provoquer une <span style="color: #0000ff;">IOException </span>si le drive n&#8217;est pas accessible.</p>
<h3>Déclaration de l&#8217;assembly et de la fonction dans SQL Server:</h3>
<p>La méthode <em>GetDrives() </em>est considérée comme <em>UNSAFE</em>, en raison du type d&#8217;appels qu&#8217;elle effectue vers le kernel pour récupérer les propriétés et les tailles des disques. Pour charger l&#8217;assembly dans SQL Server, il faut activer &#8216;<em>clr enabled</em>&#8216; et paramétrer la base pour accepter de charger des assemblies UNSAFE:</p>
<pre><span style="color: #0000ff;">sp_configure '<span style="color: #008000;">clr enabled</span>',1
GO
reconfigure
GP
alter database clrtest set trustworthy on
GO</span></pre>
<p>Enfin, créer l&#8217;assembly et la fonction:</p>
<pre><span style="color: #0000ff;">use clrtest
GO
CREATE ASSEMBLY fixeddrives from '<span style="color: #008000;">E:\CAPDATA\DEV\CLR\fn_fixeddrives\bin\Debug\fn_fixeddrives.dll</span>' WITH PERMISSION_SET = UNSAFE
GO
CREATE FUNCTION fn_fixeddrives ()
RETURNS TABLE ("<span style="color: #008000;">Drive</span>" nvarchar(3), "<span style="color: #008000;">Size(Mb)</span>" bigint, "<span style="color: #008000;">Used(Mb)</span>" bigint, "<span style="color: #008000;">Available(Mb)</span>" bigint, "<span style="color: #008000;">Use%</span>" bigint)
AS EXTERNAL NAME fixeddrives.cFixedDrives.fn_fixeddrives
GO</span></pre>
<p>Finalement:</p>
<pre><span style="color: #0000ff;">select * from fn_fixeddrives()
GO
</span></pre>
<pre><span style="color: #0000ff;">Drive   Size(Mb)  Used(Mb)  Available(Mb)    Use%
----    --------  --------  --------------   -----
C:\	39997	  27403	    12593	     68
E:\	205244	  129893    75350	     63
G:\	76321	  18700	    57621	     24
V:\	60000	  30254	    29746	     50</span></pre>
<p>A+ David B.</p>
<p><strong>* Note</strong>: <em>A noter qu&#8217;un <a href="http://www.mssqltips.com/tip.asp?tip=1986">précédent </a>existe et a été publié  par Andy Novick dans mssqltips.com, mais sa fonction ne filtre pas sur les lecteurs DVD ou CD, et elle est obligée de passer par des pseudo-types SQL (sqlint64) pour tenir compte des colonnes nullable.<br />
</em></p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">C    12594<br />
E    75350<br />
G    57621<br />
V    29746</div>
<p><script src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO" type="text/javascript"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/sql-server-principes-dune-sauvegarde-a-chaud/" rel="bookmark" title="12 décembre 2008">Principes d&#8217;une sauvegarde à chaud</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 2.630 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%2Fune-alternative-a-xp_fixeddrives%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fune-alternative-a-xp_fixeddrives%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/JgaEXpqk9rQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/une-alternative-a-xp_fixeddrives/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/une-alternative-a-xp_fixeddrives/</feedburner:origLink></item>
		<item>
		<title>Scripting et SMO (suite): scripter les objets directement en T-SQL</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/iQPv6hWTyFg/</link>
		<comments>http://blog.capdata.fr/index.php/scripting-et-smo-suite-scripter-les-objets-directement-en-t-sql/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 14:45:24 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[DDL]]></category>
		<category><![CDATA[ole automation]]></category>
		<category><![CDATA[SCRIPT]]></category>
		<category><![CDATA[SMO]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1343</guid>
		<description><![CDATA[Suite de l&#8217;article précédent, où il était question de générer le DDL d&#8217;une base avec C# et SMO. Si on pousse l&#8217;idée un peu plus loin, il serait séduisant de pouvoir le faire directement dans une procédure stockée, en s&#8217;interfaçant avec SMO et sa méthode Script(). La première solution qui vient à l&#8217;esprit, c&#8217;est évidemment [...]]]></description>
			<content:encoded><![CDATA[<p>Suite de l&#8217;article <a href="http://blog.capdata.fr/index.php/generer-le-ddl-complet-dune-base-en-csmo/">précédent</a>, où il était question de générer le DDL d&#8217;une base avec C# et SMO. Si on pousse l&#8217;idée un peu plus loin, il serait séduisant de pouvoir le faire directement dans une procédure stockée, en s&#8217;interfaçant avec SMO et sa méthode Script(). La première solution qui vient à l&#8217;esprit, c&#8217;est évidemment SQLCLR.</p>
<h2>SQLCLR vs COM Automation:</h2>
<p>Seulement voilà, on s&#8217;y casse un peu les dents car comme le dit <a href="http://sqlkpi.com/blogs/bobb/post/Two-things-you-cant-do-in-SQLCLR.aspx">Bob Beauchemin</a>, SMO n&#8217;est pas supporté dans SQLCLR. Donc à priori, adieu la méthode Script(), et retour au clic-droit &#8230;</p>
<p>Cet article propose une alternative qui utilise  <strong>COM Automation</strong> (ou OLE Automation). C&#8217;est une fonctionnalité qui permet de charger un composant COM et d&#8217;utiliser ses méthodes grâce à des procédures stockées étendues sp_OA&#8230; C&#8217;est un peu l&#8217;ancêtre de SQLCLR, mais avec moins de restrictions, donc plus de risques à l&#8217;utilisation, c&#8217;est la raison pour laquelle cette technique est pas mal décriée.</p>
<p>D&#8217;ailleurs, en théorie <strong>utiliser du SMO avec OLE Automation n&#8217;est pas supporté par SQL Server</strong>, pour des raisons de sécurité du code notamment, parce que par défaut la DLL externe que l&#8217;on souhaite utiliser est chargée dans le process address space du moteur, ce qui augmente le risque d&#8217;écraser de la mémoire liée à SQL Server et de crasher le processus tout entier ou de provoquer des fuites mémoire. Il existe tout un tas de recommandations contre l&#8217;usage de COM Automation avec SQL Server, et  beaucoup de cas ont été ouverts au support à cause de ça. Il faut à chaque fois que c&#8217;est possible lui préférer l&#8217;utilisation de SQLCLR. Sauf que dans notre cas, SMO n&#8217;étant  pas utilisable dans du SQLCLR, il ne reste que peu d&#8217;options.</p>
<p>Une technique acceptable pour utiliser COM Automation sans mettre en péril l&#8217;instance est de charger le COM dans un processus séparé et dédié, pour que tout problème de pointeur NULL ou de  garbage collection dans le COM n&#8217;affecte pas SQL Server. Par exemple dans un web service accessible par Service Broker comme le propose <a href="http://smointsql.codeplex.com/">Simon Sabin</a>, ou dans un serveur COM+ comme nous allons le voir ici. Donc en résumé:</p>
<p style="text-align: center;"><a href="http://blog.capdata.fr/wp-content/uploads/2010/08/Sans-COM_usage5.jpg"><img class="size-full wp-image-1410 aligncenter" title="Sans COM_usage" src="http://blog.capdata.fr/wp-content/uploads/2010/08/Sans-COM_usage5.jpg" alt="" width="681" height="259" /></a></p>
<h2>Ecrire le COM object:</h2>
<p>COM est un truc énorme et je ne peux pas en parler dans un article. Il faudrait un bon millier de pages pour décrire ce que c&#8217;est dans les détails et ce que ça fait, mais disons que l&#8217;idée derrière COM est qu&#8217;un objet puisse publier ses classes et ses méthodes pour permettre à des applications tierces de pouvoir les utiliser sans pour autant divulguer son code source. Les objets COM existent le plus souvent sous la forme de librairies dynamiques (DLL). Le principe est utilisé massivement dans à peu près toutes les applications Windows MFC ou Console, y compris SQL Server.</p>
<p><strong>Pour pouvoir être réutilisé, un objet COM doit posséder les caractéristiques suivantes:</strong><br />
- Ses classes doivent être publiques et implémenter une interface publique.<br />
- Chaque classe doit posséder un constructeur par défaut (vide).<br />
- La DLL doit être signée.<br />
- La DLL doit être enregistrée sur la machine sur laquelle on va l&#8217;utiliser.</p>
<p>Par exemple pour scripter juste une table:</p>
<pre><span style="color: #0000ff;">using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;

namespace getDDL
{
     public interface IgetDDL    <span style="color: #008000;">// &lt;- 1</span>
     {
         string ddlThis(string _srvname, string _dbname, int _objid);
     }
     public class cgetDDL : IgetDDL    <span style="color: #008000;"> // &lt;- 2</span>
     {
         string ddlstr;

         public cgetDDL() { }    <span style="color: #008000;"> // &lt;- 3</span>

         public string ddlThis(string _srvname, string _dbname, int _objid)     <span style="color: #008000;">// &lt;- 4</span>
         {           
             Server Srv = new Server(_srvname);
             Database Db = new Database();
             Db = Srv.Databases[_dbname];
             StringCollection _tablescr = Db.Tables.ItemById(_objid).Script();

             foreach (string _line in _tablescr)
<span style="color: #0000ff;">                 ddlstr += _line;
</span></span><span style="color: #0000ff;">             ddlstr += "GO"+'\n';

             IndexCollection _indexes = _t.Indexes;
             foreach (Index _i in _indexes)
             {
                 StringCollection _iscr = _i.Script();
                 foreach (string _line in _iscr)
                     ddlstr += _line + '\n';
             }
             if (_indexes.Count != 0)
                 ddlstr += "GO" + '\n';

             CheckCollection _checks = _t.Checks;
             foreach (Check _c in _checks)
             {
                 StringCollection _cscr = _c.Script();
                 foreach (string _line in _cscr)
                     ddlstr += _line + '\n';
             }
             if (_checks.Count != 0)
                 ddlstr += "GO" + '\n';

             TriggerCollection _triggers = _t.Triggers;
             foreach (Trigger _trg in _triggers)
             {
                 StringCollection _trgscr = _trg.Script();
                 foreach (string _line in _trgscr)
                     ddlstr += _line + '\n';
             }
             if (_triggers.Count != 0)
                 ddlstr += "GO" + '\n';

             foreach (Column _col in _t.Columns)
             {
                 if (_col.DefaultConstraint != null)
                 {
                     StringCollection _def = _col.DefaultConstraint.Script();
                     foreach (string _line in _def)
                         ddlstr += _line + '\n';
                     ddlstr += "GO" + '\n';
                 }
            }</span>
<span style="color: #0000ff;">
             return ddlstr;
         }
     }
}</span></pre>
<p><strong>&#8211;&gt; </strong><strong>1:</strong> Déclaration de l&#8217;interface publique, qui va publier aux applications externes l&#8217;unique méthode de la classe CgetDDL :: ddlThis()<br />
<strong>&#8211;&gt;</strong> <strong>2:</strong> Déclaration de la classe publique qui implémente l&#8217;interface.<br />
<strong>&#8211;&gt; 3: </strong>Déclaration de son constructeur par défaut.<br />
<strong>&#8211;&gt;</strong> <strong>4: </strong>Déclaration de la méthode, qui prend en arguments le nom de l&#8217;instance, le nom de la base et l&#8217;object_id de la table à scripter. Pour le reste, cf l&#8217;<a href="http://blog.capdata.fr/index.php/generer-le-ddl-complet-dune-base-en-csmo/">article précédent</a>.</p>
<p>Il faudra également modifier la propriété <strong>ComVisible </strong>de l&#8217;assembly pour permettre d&#8217;y accéder depuis l&#8217;extérieur. Dans assembly.cs:</p>
<pre><span style="color: #0000ff;">[assembly: ComVisible(<span style="color: #008000;">true</span>)]</span></pre>
<p>Enfin, il faut signer la DLL avec un nom fort que l&#8217;on pourra générer avec VS:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/08/sign_assembly.jpg"><img class="alignnone size-full wp-image-1421" title="sign_assembly" src="http://blog.capdata.fr/wp-content/uploads/2010/08/sign_assembly.jpg" alt="" width="770" height="404" /></a></p>
<h2>Chargement du COM dans un serveur COM+:</h2>
<p>Une fois la DLL compilée, il va falloir l&#8217;enregistrer sur la machine et générer un fichier Type Library (*.tlb) que l&#8217;on va utiliser ensuite dans le serveur COM+. Pour enregistrer une dll et générer le tlb, on utilise l&#8217;utilitaire <strong>regasm </strong>qui est fournit avec tous les frameworks .NET (et qui doit se trouver qq part sous C:\Windows\Microsoft .NET\Framework\&#8230;):</p>
<pre><span style="color: #0000ff;">DOS &gt;regasm /codebase getDDL.dll /tlb:getDDL.tlb
<em>Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.3053
Copyright (C) Microsoft Corporation 1998-2004. Tous droits réservés.</em>

Inscription des types réussie
L'assembly a été exporté vers 'C:\DBA\DEV\C#\getDDL\bin\Debug\getDDL.tlb' et la bibliothèque de types a été inscrite avec succès</span></pre>
<p>A partir de là, on va créer un nouveau serveur COM+ en utilisant le service de composants <em><strong>comexp.msc</strong></em>: dans <em>Services des composants -&gt; Ordinateurs -&gt; Poste de travail -&gt; Applications COM+</em>, on créé une nouvelle application serveur vide, démarrée sous un compte windows qui serait reconnu comme sysadmin sur l&#8217;instance (par exemple l&#8217;admin local, ou tout autre compte windows sysadmin). On dépose ensuite le fichier tlb dans les composants de la nouvelle application COM+, et on vérifie si la méthode est bien exposée:</p>
<p style="text-align: center;"><a href="http://blog.capdata.fr/wp-content/uploads/2010/08/COMP.jpg"><img class="size-full wp-image-1435 aligncenter" title="COMP" src="http://blog.capdata.fr/wp-content/uploads/2010/08/COMP.jpg" alt="" width="408" height="305" /></a></p>
<p>Enfin on démarre le serveur COM+, et on vérifie qu&#8217;un nouveau processus hôte de dll (dllhost.exe) est bien démarré avec le bon compte. On va pouvoir s&#8217;intéresser à la partie T-SQL.</p>
<h2>Ecriture de la procédure stockée:</h2>
<p>Avant toute chose, pour pouvoir autoriser SQL Server à utiliser Ole Automation, il faut l&#8217;activer dans les paramètres de configuration:</p>
<pre><span style="color: #0000ff;">sp_configure '<span style="color: #ff0000;">Ole Automation Procedures</span>',1;
GO
reconfigure;
GO</span></pre>
<p>Ensuite, on créé la procédure stockée qui va charger le COM et utiliser la méthode ddlThis():</p>
<pre><span style="color: #0000ff;">create procedure usp_getDDL (@tablename varchar(128))
AS
BEGIN
     DECLARE @hr int, @obj int;
     DECLARE @Source nvarchar(255), @Desc nvarchar(255);
     DECLARE @DDLTEXT nvarchar(4000);
     DECLARE @dbname sysname, @objid int, @srvname sysname;

     select @srvname = @@servername
     select @dbname= db_name()
     select @objid = object_id(@tablename)
     if (@objid is NULL)
     BEGIN
         print 'Table '+@tablename+' non trouvee dans la base courante'
         RETURN
     END

     execute @hr = sp_OACreate '<span style="color: #ff0000;">getDDL.cgetDDL</span>', @obj OUT,<span style="color: #ff0000;"> 4         <span style="color: #008000;"> --&gt; context = 4 =&gt; </span></span></span><span style="color: #008000;">COM stocké dans un dllhost.exe, pas dans sqlservr.exe</span><span style="color: #0000ff;">
     if (@hr &lt;&gt; 0)
     BEGIN
         EXEC sp_OAGetErrorInfo @obj,
         @Source OUT,
         @Desc OUT;
         SELECT HR = convert(varbinary(4),@hr),
         Source=@Source,
         Description=@Desc;
         RETURN
     END

     execute @hr = sp_OAMethod @obj, '<span style="color: #ff0000;">ddlThis</span>', @DDLTEXT OUT, @srvname, @dbname, @objid
     if (@hr &lt;&gt; 0)
     BEGIN
         EXEC sp_OAGetErrorInfo @obj,
         @Source OUT,
         @Desc OUT;
         SELECT HR = convert(varbinary(4),@hr),
         Source=@Source,
         Description=@Desc;
         RETURN
     END

     execute @hr = sp_OADestroy @obj

     select @DDLTEXT as 'DDL'
END</span></pre>
<p>La procédure récupère le nom de la table, vérifie si celle-ci existe dans la base courante, et charge le COM dans le dllhost.exe avec <strong>sp_OACreate</strong>. Le nom du COM object est celui déclaré dans le serveur COM+ . Un autre paramètre d&#8217;extrême importance est le dernier passé à sp_OACreate  (4). <strong>Il s&#8217;agit du contexte de chargement du COM, </strong>dans ce cas 4 indique à SQL Server que le composant sera chargé en dehors de son process address space et ne peut avoir accès aux ressources mémoire dans sqlservr.exe (cf <a href="http://msdn.microsoft.com/en-us/library/ms189763.aspx">MSDN</a>). C&#8217;est notre garde-fou et c&#8217;est indispensable, car par défaut, la ddl aurait été chargée dans sqlservr.exe et aurait pû causer des dégâts, il est donc très important de procéder de cette manière.</p>
<p>Ensuite la procédure appelle <strong>sp_OAMethod</strong> pour invoquer la méthode exposée par l&#8217;interface du COM, et récupère le DDL dans un nvarchar(4000). A la fin du processus, la référence vers l&#8217;objet est détruite avec <strong>sp_OADestroy</strong>.</p>
<p>A l&#8217;appel de la procédure:</p>
<pre><span style="color: #0000ff;">DOS&gt;sqlcmd -E
1&gt; use CAPDATA
2&gt; go
Le contexte de la base de données a changé ; il est maintenant 'CAPDATA'.
1&gt; exec usp_getddl 'ANNONCE'
2&gt; go

<em>DDL
------------------------------------------------------------------------------------------------------</em>

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[ANNONCE](
 [ID_ANNONCE] [int] NOT NULL,
 [ID_JOURNAL] [int] NOT NULL,
 [ID_PROPALOUER] [int] NOT NULL,
 [DATETIME_ANNONCE] [datetime] NOT NULL,
 [PRIX] [numeric](6, 2) NULL,
 [NB_PARUTION] [int] NULL
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[ANNONCE] ADD  CONSTRAINT [PK_ANNONCE] PRIMARY KEY CLUSTERED
(
 [ID_ANNONCE] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF,
ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO</span></pre>
<h2>Conclusion:</h2>
<p>COM ou Ole Automation est une technique pour faire communiquer SQL Server avec des composants externes. Elle  présente des risques élevés de corruption mémoire lorsqu&#8217;on l&#8217;utilise avec les paramètres de contexte par défaut, mais lorsqu&#8217;on manipule l&#8217;objet à travers son propre conteneur, les risques sont limités.</p>
<p>Dans la mesure où SMO n&#8217;est pas supporté avec SQLCLR, elle représente une alternative intéressante pour pouvoir interfacer SQL Server avec des fonctions qui ne sont pas disponibles ailleurs.</p>
<p>A+. David B.</p>
<p><script src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO" type="text/javascript"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/" rel="bookmark" title="11 décembre 2008">Modes de récupération et journal de transactions, épisode 2</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</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/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/saines-lectures/" rel="bookmark" title="25 août 2010">Saines lectures</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.323 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%2Fscripting-et-smo-suite-scripter-les-objets-directement-en-t-sql%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fscripting-et-smo-suite-scripter-les-objets-directement-en-t-sql%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/iQPv6hWTyFg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/scripting-et-smo-suite-scripter-les-objets-directement-en-t-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/scripting-et-smo-suite-scripter-les-objets-directement-en-t-sql/</feedburner:origLink></item>
		<item>
		<title>Mythe: SQL Server associe un thread à chaque connexion</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/PFQTeviDvN8/</link>
		<comments>http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 21:52:40 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[sqlos]]></category>
		<category><![CDATA[thread]]></category>
		<category><![CDATA[worker]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1283</guid>
		<description><![CDATA[C&#8217;est évidemment faux, mais il est facile de se méprendre sur la question. Pourtant il existe une manière simple de le vérifier. Sur une instance non-idle (avec de l&#8217;activité), il suffit de récupérer plusieurs fois de suite la valeur de os_thread_id associé à sa propre connexion:
select os_thread_id from sys.dm_os_threads T
inner join sys.dm_os_workers W on W.worker_address [...]]]></description>
			<content:encoded><![CDATA[<p>C&#8217;est évidemment faux, mais il est facile de se méprendre sur la question. Pourtant il existe une manière simple de le vérifier. Sur une instance non-idle (avec de l&#8217;activité), il suffit de récupérer plusieurs fois de suite la valeur de os_thread_id associé à sa propre connexion:</p>
<pre><span style="color: #0000ff;">select os_thread_id from sys.dm_os_threads T
inner join sys.dm_os_workers W on W.worker_address = T.worker_address
inner join sys.dm_os_tasks TA on TA.task_address = W.task_address
inner join sys.dm_exec_requests R on R.session_id = TA.session_id
where R.session_id = <span style="color: #ff00ff;">@@spid<span style="color: #0000ff;">;</span>
<span style="color: #0000ff;">GO</span></span></span></pre>
<p>Vous verrez qu&#8217;il finit par changer, et pourtant la connexion n&#8217;a pas été interrompue. L&#8217;explication réside dans le modèle de planification adopté par SQL Server depuis 1997 (la 7.0)</p>
<h2>Tasks et Workers:</h2>
<p>Dans SQL Server, la requête SQL ou l&#8217;initialisation de la connexion est une <strong>tâche </strong>(<em>sys.dm_os_tasks</em>). Le porteur de l&#8217;exécution de la tâche est le <strong>worker</strong> (<em>sys.dm_os_workers</em>). L&#8217;idée principale est la suivante: pour pouvoir supporter de nombreuses  exécutions de batches SQL, il faut dissocier la tâche  (task) de l&#8217;exécutant (worker), ce qui permet à un même worker d&#8217;exécuter plusieurs tâches successivement. Si vous ouvrez deux connexions sur un système idle, et que dans chaque session vous exécutez la requête ci-dessus, vous avez des chances de tomber sur le même os_thread_id, c&#8217;est la preuve que le worker est dissocié de la session ou de la tâche à exécuter. L&#8217;objectif est de maintenir un worker en exécution tant qu&#8217;il reste des choses à faire.</p>
<h2>Organisation des workers:</h2>
<p>Les workers sont regroupés par scheduler (UMS ou SQLOS) dans un pool, dont la taille maximale est définie telle que =  (max worker threads / nb of user schedulers). Au cours de l&#8217;exécution, les workers sont répartis dans différentes listes:<br />
- <strong>worker-list</strong>:  les workers y sont stationnés au démarrage de SQL Server. A cet instant là, aucune tâche n&#8217;est arrivée au moteur d&#8217;exécution.<br />
- <strong>runnable-list</strong>:  à chaque nouvelle tâche qui arrive, un worker est pris dans la  worker-list, lié à la tâche et placé dans la runnable-list. Il est initialisé en attente infinie sur un &#8216;<em>event</em>&#8216; privé en utilisant la primitive <em>WaitForSingleObject(). </em>L&#8217;event est un objet du noyau windows  qui sert comme un drapeau levé ou baissé à signaler à un worker qu&#8217;il  peut poursuivre son exécution. N&#8217;importe quel worker peut prendre n&#8217;importe quelle  tâche. La runnable-list est l&#8217;antichambre de l&#8217;exécution.<br />
- <strong>waiter-list</strong>: lorsqu&#8217;une tâche doit attendre la fin d&#8217;une opération (la libération d&#8217;une ressource comme un latch par exemple), elle est placée en waiter-list. C&#8217;est à la charge du worker qui détient la ressource de lui indiquer que la ressource est libérée.<br />
- <strong>I/O-list</strong>: toutes les tâches en attente de retour d&#8217;une I/O asynchrone sont chaînées dans cette liste. C&#8217;est le worker  qui rend la main qui exécute les routines de completion d&#8217;I/Os et qui replace ces workers dans la runnable-list ensuite (cf  section suivante).<br />
- <strong>timer-list</strong>:  gère toutes les tâches en attente de l&#8217;expiration d&#8217;un timer (comme une trace SQL avec une durée d&#8217;exécution&#8230;). Comme pour les workers en I/O list, elles sont remises dans la runnable-list par le worker qui rend la main.</p>
<h2>Cycle de l&#8217;exécution:</h2>
<p>Lorsque c&#8217;est à son tour, le premier worker dans la runnable-list se voit signaler son event par le worker qui rend la main (= yield), et il peut passer en exécution. A son tour ensuite, il va exécuter sa tâche plus un certain nombre de sub-routines comme par exemple vérifier la liste des I/Os asynchrones en attente et lancer les routines de completion d&#8217;I/Os, vérifier la liste des workers en attente d&#8217;éveil en timer list, et vérifier l&#8217;expiration de certains timers, enfin signaler l&#8217;event du worker en tête de runnable-list et se replacer en worker-list en attendant une nouvelle tâche à exécuter.</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/08/scheduling.png"><img class="alignnone size-medium wp-image-1333" title="scheduling" src="http://blog.capdata.fr/wp-content/uploads/2010/08/scheduling-300x221.png" alt="" width="300" height="221" /></a></p>
<p>Si l&#8217;instance est peu sollicitée, le même worker peut se retrouver à exécuter plusieurs batches différents à la suite en repassant par la worker-list, la runnable-list puis en exécution. C&#8217;est ce qui donne l&#8217;impression qu&#8217;une connexion  est toujours sur le même thread, alors que c&#8217;est juste parce que les autres workers n&#8217;ont rien à faire de particulier et restent en worker-list. Il n&#8217;y a qu&#8217;un seul cas où un nouveau worker est créé lorsqu&#8217;une nouvelle connexion arrive, c&#8217;est lorsque la worker-list est vide et que tous les workers sont répartis dans les différentes listes waiter, timer, I/O ou runnable. Tant que la valeur de max worker threads n&#8217;est pas atteinte, SQL Server créé un nouveau worker et le place avec la tâche de gérer la nouvelle connexion en runnable-list, mais encore une fois, le worker n&#8217;est pas lié à la connexion. Une fois revenu en worker-list, il prendra une tâche en provenance d&#8217;une autre connexion.</p>
<h2>En résumé:</h2>
<p>Ce qu&#8217;il faut se dire, c&#8217;est qu&#8217;une instance n&#8217;a pas besoin de 1000 threads pour servir 1000 connexions simultanées. De nombreuses connexions restent idle, et il est très rare de devoir manuellement augmenter la valeur de max worker threads même avec une très forte activité et de nombreux utilisateurs. Quelques workers suffisent, et grâce à son système de planification coopératif, SQL Server peut absorber la charge aisément.</p>
<p>En ce sens, la vision que renvoient les DMV sys.dm_exec_sessions et sys.dm_exec_connections est beaucoup plus consistante avec la réalité que ne l&#8217;était sysprocesses. Une session en AWAITING COMMAND n&#8217;avait pas de thread associé, c&#8217;était vaguement une instance de classe chaînée avec d&#8217;autres dans une liste.  A partir de SQL Server 2005, seule sys.dm_exec_sessions est liée aux tables de tasks, workers et threads. sys.dm_exec_connections reste à part, ce qui avait tendance à dérouter au début mais qui au final s&#8217;avère beaucoup plus logique.</p>
<p>A+ David B.</p>
<p><script src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO" type="text/javascript"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/" rel="bookmark" title="30 mars 2010">Un trigger fait-il parti d&#8217;une transaction ?</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/saines-lectures/" rel="bookmark" title="25 août 2010">Saines lectures</a> (David BAFFALEUF) [SQL Server]</li>
<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/sql-server-regles-dinstallation-de-base-episode-1/" rel="bookmark" title="18 juin 2009">Règles d&#8217;installation de base (épisode 1)</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.686 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%2Fmythe-sql-server-associe-un-thread-a-chaque-connexion%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmythe-sql-server-associe-un-thread-a-chaque-connexion%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/PFQTeviDvN8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/</feedburner:origLink></item>
		<item>
		<title>Générer le DDL complet d’une base en C# / SMO / multithreading</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/XxIcbR1VV-U/</link>
		<comments>http://blog.capdata.fr/index.php/generer-le-ddl-complet-dune-base-en-csmo/#comments</comments>
		<pubDate>Thu, 29 Jul 2010 22:05:08 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[getmsddlmt]]></category>
		<category><![CDATA[multithreading]]></category>
		<category><![CDATA[SCRIPT]]></category>
		<category><![CDATA[SMO]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1136</guid>
		<description><![CDATA[Pour faire suite à un post sur développez concernant l&#8217;existence d&#8217;outils de scripting d&#8217;objets en dehors de ceux proposés par SSMS, j&#8217;ai décidé de regarder d&#8217;un peu plus près le sujet et d&#8217;en créer un (getMsDDLmt) pour voir ce que ça donne. Afin de suivre  les explications du code, les sources sont disponibles sur SourceForge.
Je [...]]]></description>
			<content:encoded><![CDATA[<p>Pour faire suite à un<a href="http://www.developpez.net/forums/d945501/bases-donnees/ms-sql-server/administration/recuperer-script-base/"> post</a> sur développez concernant l&#8217;existence d&#8217;outils de scripting d&#8217;objets en dehors de ceux proposés par SSMS, j&#8217;ai décidé de regarder d&#8217;un peu plus près le sujet et d&#8217;en créer un (<em>getMsDDLmt</em>) pour voir ce que ça donne. Afin de suivre  les explications du code, les sources sont disponibles sur <a href="http://sourceforge.net/projects/getmsddlmt/">SourceForge</a>.</p>
<p>Je vais juste détailler un peu les points qui sortent de l&#8217;ordinaire dans le programme. Il s&#8217;appuie comme la plupart des outils de ce genre sur <a href="http://msdn.microsoft.com/en-us/library/ms162557.aspx">SMO</a> et<a href="http://msdn.microsoft.com/en-us/library/618ayhy6.aspx"> C#</a>.</p>
<h2>Comment générer le script d&#8217;un objet en SMO:</h2>
<p>L&#8217;objet au sommet de la hiérarchie des objets SMO pour ce qui nous intéresse est <span style="color: #333333;"><strong>Database</strong></span>:</p>
<pre><span style="color: #333333;">Microsoft.SqlServer.Management.Smo.Database
                                    |__ Users
                                    |__ Schemas
                                    |__ Role
                                    |__ Table
                                    |__ View
                                    |__ StoredProcedure
                                    |__ UserDefinedFunction
                                    |__ etc...</span>
</pre>
<p>Chaque sous-objet de la hiérarchie de <em>Database </em>possède une méthode <em>script()</em> qu&#8217;il suffit d&#8217;invoquer, et qui renvoie une <em>StringCollection</em>. Il suffit d&#8217;afficher chaque item de la collection pour obtenir le script de tous les objets. Par exemple pour sortir toutes les UDF:</p>
<pre><span style="color: #0000ff;">Server Srv  = new Server(".");
Database Db = Srv.Databases["AdventureWorks"];

UserDefinedFunctionCollection _func = Db.UserDefinedFunctions;
foreach (UserDefinedFunction _f in _func)
{
     StringCollection _fscr = _f.Script();
     foreach (string _line in _fscr)
         Console.WriteLine(_line);
}
Console.WriteLine("GO");</span>
</pre>
<p>Vous remarquerez qu&#8217;il n&#8217;y a pas explicitement de connexion, elle est réalisée dans le constructeur de <em>Srv</em>. Une fois que la base est instanciée, on récupère notre collection d&#8217;UDF, et pour chaque fonction on applique la fonction <em>script()</em>. Comme<em> script()</em> renvoie elle aussi une collection, on est encore obligé de boucler pour afficher chaque ligne.</p>
<p><strong>Bien que relativement simple sur le papier, ça n&#8217;est pas sans poser de gros soucis dans la réalité:</strong><br />
- Il faut faire attention de filtrer les objets systèmes car il n&#8217;y a pas de distinction entre une vue système et une vue utilisateur dans la classe View, ou la classe StoredProcedure.<br />
- La méthode Script() ne peut pas être appelée si l&#8217;objet a été encrypté (par exemple une fonction ou une procédure stockée).<br />
- Dans un programme simple, la génération du DDL est sérialisée: elle n&#8217;est effectuée que par un seul thread.<br />
- Ca pollue le plan cache avec des tonnes de plans ad hoc qui sont sans cesse recompilés.</p>
<h3>Résultat, la génération du DDL par la méthode classique est affreusement lente:</h3>
<ul>
<li><strong>Compilation des plans ad hoc:</strong> c&#8217;est le le premier facteur en termes de temps de réponse. Une manière simple de le voir est de lancer la génération deux fois de suite. La seconde fois, le script complet sera généré beaucoup plus vite. Pour pallier ce problème, pas beaucoup de solutions: passer la base en PARAMETERIZATION = FORCED pour que l&#8217;optimiseur choisisse de paramétriser aussi les plans non éligibles par défaut (avec des jointures, etc&#8230;) peut être extrêmement efficace le temps de la génération (28 secondes en FORCED contre 1 minute 30 en SIMPLE pour sortir AdventureWorks sur mon laptop avec un seul thread), mais l&#8217;impact peut quand même être important sur une base de production, car l&#8217;option s&#8217;applique à toute la base. Fort heureusement elle est dynamique et peut être retirée rapidement à la fin de la génération.</li>
</ul>
<ul>
<li><strong>Le parcours de la liste des objets à scripter: </strong> parce que pour toutes les procédures stockées, fonctions, vues il faut vérifier si l&#8217;objet n&#8217;est pas un objet système (avec <em>isSystemObject</em>) et si l&#8217;objet n&#8217;est pas encrypté (avec <em>isEncrypted</em>). Il existe une astuce qui a été révélée  par <a href="http://www.sqlteam.com/article/scripting-database-objects-using-smo-updated">Bill Graziano</a> pour accélérer un peu ce processus en pré-fetchant ces propriétés, mais globalement les gains  restent très moyens. Le plus rapide pour générer la liste des objets à filtrer reste encore d&#8217;écrire une requête qui le ferait, au moins pour filtrer les objets système, et de placer le tout dans un DataTable ADO.NET. C&#8217;est la méthode qui a été retenue pour getMsDDLmt.</li>
</ul>
<ul>
<li><strong>La sérialisation du processus</strong>: par défaut, seul un thread ferait tout le travail, sans tirer parti des multiples cores que l&#8217;on trouve aujourd&#8217;hui même sur des portables. La solution est de créer un programme <a href="http://www.gotw.ca/publications/concurrency-ddj.htm">qui utilise de multiples threads</a> pour générer le DDL des objets les plus couramment rencontrés (tables, fonctions, procédures stockées, vues, etc&#8230;)  en parallèle.</li>
</ul>
<h2>Le programme getMsDDLmt:</h2>
<p>L&#8217;objectif est d&#8217;extraire sur la console le DDL de tous les objets  d&#8217;une base en particulier. L&#8217;utilisateur peut rediriger la sortie de la  console ensuite dans un fichier.  Il  prend en argument un fichier de configuration au format XML très simple  qui ressemble à ceci:</p>
<pre><span style="color: #0000ff;">&lt;?xml version='1.0'?&gt;
&lt;Host&gt;
    &lt;Instance&gt;.&lt;/Instance&gt;
    &lt;Database&gt;AdventureWorks&lt;/Database&gt;
&lt;/Host&gt;</span></pre>
<p>Le point représente l&#8217;instance locale, si vous avez une instance  nommée il faudra renseigner son nom complet. L&#8217;authentification est  supposée en mode intégrée, la raison pour laquelle on ne passe pas de  user, de mot de passe, etc&#8230;</p>
<p>Un appel au programme s&#8217;effectue donc comme ceci:</p>
<pre><span style="color: #0000ff;">DOS&gt;getMsDDLmt -I myConfigFile.xml &gt; maBase.sql</span>
</pre>
<p>Les  étapes critiques étant la constitution de la liste d&#8217;objets  et la partie multithreading, je vais surtout m&#8217;attarder sur ces deux points principaux.</p>
<h3>1ère étape: prise de l&#8217;environnement et des variables principales ( <em>Main()</em> ):</h3>
<p>C&#8217;est le véritable début, une fois les paramètres récupérés depuis le fichier de config XML, il faut tenter d&#8217;initier la connexion à l&#8217;instance et à la base. Quelques tests basiques sont effectués pour trapper une instance qui n&#8217;existe pas ou qui ne serait pas démarrée, par exemple. Tout cela a lieu dans le point d&#8217;entrée principal du programme:</p>
<pre> <span style="color: #008000;">// Validation de la connexion et de la base </span>
 <span style="color: #0000ff;">try
 {
     Srv = new Server(_srv);
     if (Srv.Databases.Contains(_dbname))
     {
         Db = Srv.Databases[_dbname];
     }
     else
     {
         Console.WriteLine("La base " + _dbname + " n'a pas été trouvée");
         return;
     }
 }
 catch(Exception exsql)
 {
     Console.WriteLine("Une erreur est survenue dans le module: "+exsql.Source+" : "+exsql.Message);
     Console.WriteLine("Vérifiez le nom de l'instance dans le fichier "+ _xmlcfg +" et vérifiez que celle-ci est bien démarrée");
     return;
 }</span>

<span style="color: #008000;"> // Test de la version de SQL Server. Supporté 9+</span>
<span style="color: #0000ff;"> if (Srv.Information.Version.Major &lt; 9)
 {
     Console.WriteLine("Version de SQL Server supportée à partir de SQL Server 2005 et plus");
     Usage();
     return;
 }</span>

 <span style="color: #008000;">// Revision 1.1: l'appel à la méthode Script() sur un objet encrypté retourne une exception non gérée de type PropertyCannotBeRetrievedException.
 // On fetche donc la propriété dès le départ pour pouvoir la tester plus rapidement.</span>
 <span style="color: #0000ff;">Srv.SetDefaultInitFields(typeof(StoredProcedure), "IsEncrypted");
 Srv.SetDefaultInitFields(typeof(View), "IsEncrypted");
 Srv.SetDefaultInitFields(typeof(UserDefinedFunction), "IsEncrypted");</span>

<span style="color: #008000;"> // Récupération de la liste des objet et alimentation du DataTable.</span>
<span style="color: #0000ff;"> _DT_ObjList = getUsrObjList();</span>
</pre>
<p>La partie intéressante est celle qui concerne la Revision 1.1. C&#8217;est la mise en place du workaround de Bill Graziano, pour permettre de pré-fetcher la propriété <em>isEncrypted</em> pour les procédures, fonctions et vues, et d&#8217;y accéder plus rapidement ensuite. La dernière ligne affecte au DataTable global <em>_DT_ObjList</em> la liste des objets à scripter, en utilisant la fonction <em>getUsrObjList()</em>.</p>
<h3>2ième étape: lister les objets à scripter par les threads ( <em>getUsrObjList() )</em>:</h3>
<p>La liste va constituer le panier dans lequel les worker threads vont venir piocher les objets à scripter. Elle est constituée  d&#8217;une requête qui va placer l&#8217;object_id et le type d&#8217;objet dans un objet DataTable:</p>
<pre><span style="color: #008000;">/* ================================================================================================================
 *               Peuplement de La liste des objets à scripter par le Main Thread.
 *               
 * Le plus efficace revient à récupérer directement la liste des objets user dans un DataTable,
 * plutôt que de boucler sur chaque collection.On ne fait qu'un seul appel à la base pour tout
 * récupérer d'un coup.On ordonne par type asc pour que les vues (V) soient créées après les
 * tables (U)
 * */</span>
 <span style="color: #0000ff;">static DataTable getUsrObjList()
 {
     String _sqlText = @"<span style="color: #993300;">select object_id, type from </span>" + _dbname + @"<span style="color: #993300;">.sys.objects
                        where isnull(OBJECTPROPERTY(object_id,'IsMSShipped'),0) = 0
                        and type in ('P','FN','R','SN','U','V')
                        and name not in ('sysdiagrams','sp_upgraddiagrams','sp_helpdiagrams',
                        'sp_helpdiagramdefinition','sp_creatediagram','sp_renamediagram',
                        'sp_alterdiagram','sp_dropdiagram','fn_diagramobjects')
                         order by type asc</span>";

     DataTable _DT_ObjList = new DataTable();
     String _cnStr = "server=" + _srv + ";trusted_connection=yes";
     SqlConnection _cnx = new SqlConnection(_cnStr);
     SqlDataAdapter _sqlDataAdapt = new SqlDataAdapter(_sqlText, _cnx);

     try
     {
         _cnx.Open();
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.ToString());
     }

     try
     {
         _sqlDataAdapt.Fill(_DT_ObjList);
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.ToString());
     }

     return _DT_ObjList;
 }</span></pre>
<p>On effectue déjà pas mal de filtres, en ne retenant pas les objets liés aux diagrammes dans SSMS, et les objets systèmes. Malheureusement il n&#8217;existe pas de propriété pour identifier les fonctions ou procédures qui auraient été encryptées, donc ont sera obligé de le faire au moment de la génération. On ne recherche que les objets de type Procédures stockées (P), UDF (FN), règles (R), synonymes (SN), tables (U) et vues (V). Les indexes, triggers, et contraintes check seront générées lors du passage sur la table donc ils ne sont pas mentionnés explicitement dans la liste.</p>
<p>Les autres objets de la base (la base elle-même, les users, roles, schémas, fonctions et schémas de partition, etc&#8230;) seront sortis par le thread principal car ils ne présentent pas de difficulté particulière. On choisit également d&#8217;extraire les contraintes de clés étrangères après la génération des tables pour éviter les problématiques d&#8217;ordonnancement des tables dans le script (pour éviter qu&#8217;une contrainte ne soit écrite par un thread avant que la table à laquelle elle fait référence ne soit présente).</p>
<p>Le tout est placé dans un objet DataTable <em>_DT_ObjList</em>, qui est retourné au Main(), pour être ensuite parcouru par chaque worker thread.</p>
<h3>3ième étape: création des worker threads et début de script des objets ( <em>initWorker()</em> et <em>scriptThis()</em> ).</h3>
<p>Avant de rentrer dans le code, il faut peut être expliquer un peu la notion de programmation avec plusieurs threads. L&#8217;avantage d&#8217;une telle philosophie est de pouvoir tirer pleinement parti des ressources de la machine. Le problème, c&#8217;est qu&#8217;à un moment ou à un autre, les threads vont entrer en concurrence sur l&#8217;aquisition d&#8217;une ressource partagée. Dans notre cas, il s&#8217;agit de <em>_DT_ObjList</em>, la liste des objets à scripter. Il n&#8217;est pas question que deux threads parcourent la liste  en même temps et décident de scripter le même objet. Il va donc falloir trouver un moyen de les synchroniser.</p>
<p>Il existe de nombreuses méthodes pour synchroniser des threads entre eux. On distingue en gros deux grandes familles, les constructions utilisateur (comme les spinlocks ou les sections critiques en C++) et les kernel objects, qui sont des objets spécialement conçus pour ça, mais qui ont l&#8217;inconvénient de ne pas être manipulables directement dans l&#8217;espace d&#8217;adressage du programme utilisateur , et donc de nécessiter une transition vers le mode kernel à chaque fois qu&#8217;il sont invoqués.  Toutefois, la méthode la plus simple  pour synchroniser des threads en C# est d&#8217;utiliser la méthode <em>lock()</em> sur un kernel object, c&#8217;est donc celle que nous allons utiliser.</p>
<p>Concernant le nombre de threads à créer, j&#8217;ai décidé d&#8217;observer la règle suivante:  on créé 1 worker thread  pour deux CPU, pour ne pas saturer complètement la machine sur laquelle on effectue l&#8217;extraction.  La valeur est arrondie au supérieur. Donc si on a 1 ou 2 CPU, on ne créera qu&#8217;un seul worker thread, si on a 3 ou 4 CPU, on en créera 2, 5 ou 6 on en créera 3, etc&#8230;</p>
<pre><span style="color: #0000ff;">int _wtcnt = 1;
int _corecnt = System.Environment.ProcessorCount;

 if (_corecnt == 1)
 {
     _wtcnt = 1;
 }
 else
 {
     if ((_corecnt % 2) != 0)
     {
         _wtcnt = (_corecnt / 2) + 1;
     }
     else
     {
         _wtcnt = (_corecnt / 2);
     }
 }</span></pre>
<p>Ensuite on dispatche les worker threads toutes les 1 ms. Le worker va passer par son point d&#8217;entrée ( initWorker() ) et immédiatement bloquer sur le kernel object. En appelant <em>Join()</em>, le main thread va attendre que les worker threads lui signalent la fin de la génération des objets, pour qu&#8217;il puisse continuer avec les autres objets résiduels (foreign keys, fonctions et schémas de partition, etc&#8230;) .</p>
<pre><span style="color: #008000;">// Dispatch des wt toutes les 1 ms</span>
<span style="color: #0000ff;"> Thread[] _T_wt = new Thread[_wtcnt];

 for (int i = 0; i &lt; _wtcnt; i++)
 {
     _T_wt[i] = new Thread(new ThreadStart(initWorker));
     _T_wt[i].Start();
     Thread.Sleep(1);
 }</span>

<span style="color: #008000;"> // Le main Thread attend la fin de l'exécution de chaque wt</span>
<span style="color: #0000ff;"> for (int i = 0; i &lt; _wtcnt; i++)
 {
     if (_T_wt[i] != null)
     {
         _T_wt[i].Join();
     }
 }</span>
</pre>
<p>Chaque worker thread va dans le même temps bloquer sur le kernel object, et le premier qui obtient la ressource peut commencer à dépiler le DataTable pendant que les autres worker threads attendent:</p>
<pre><span style="color: #008000;">/* =================================================================================================================
 *                               Point d'entrée des wt.
 *                               
 * Chaque wt bloque sur le kernel object et dépile une ligne du DataTable à chaque fois qu'il obtient la ressource.
 * Chaque wt opére tant qu'il reste des lignes dans le DataTable.
 * */</span>
 <span style="color: #0000ff;">static void initWorker()
 {
     Server srv = new Server(_srv);
     Database _curdb = srv.Databases[_dbname];
     DataRow _DR;
     int _objid = 0;
     string _type;

     while (_DT_ObjList.Rows.Count &gt; 0)
     {</span>
         <span style="color: #008000;">// le wt courant bloque sur le kernel object pour obtenir la ligne courante</span>
         <span style="color: #0000ff;">lock (_DTlocker)
         {</span>
             <span style="color: #008000;">// On accède à chaque fois à la dernière ligne, on la stocke et on la supprime pour
             // qu'elle ne soit plus visible aux autres wt.</span>
             <span style="color: #0000ff;">_DR = _DT_ObjList.Rows[0];                    
             _objid = ((int)_DR["object_id"]);
             _type = ((string)_DR["type"]).Trim();
             _DR.Delete();
             _DR.AcceptChanges();
         }</span>

         <span style="color: #008000;">// execution du script de l'objet courant</span>
    <span style="color: #0000ff;">     try
         {
             scriptThis(_objid, _type, _curdb);
         }
         catch (Exception ex)
         {
             Console.WriteLine(ex.ToString());
         }
     }
 }</span>
</pre>
<p>Il accède toujours à la dernière ligne car à chaque fois qu&#8217;il en fetche une, il la supprime immédiatement après pour que le worker suivant puisse lire la ligne suivante (qui devient à son tour la première dans la liste). Une fois le kernel object relâché, il a stocké les informations nécessaires (object_id et type d&#8217;objet) et peut appeler scriptThis() pour scripter l&#8217;objet courant. Pendant ce temps, un autre worker a obtenu la ressource et peut dépiler son objet, etc&#8230; jusqu&#8217;à ce qu&#8217;il n&#8217;y ait plus d&#8217;éléments dans le DataTable. Allons voir maintenant ce que fait scriptThis():</p>
<pre><span style="color: #008000;">/* =========================================================================================================
 *               Script de l'objet par appel de sa méthode SMO Script()
 *               
 * Types remontés par le DataTable:
 * 'P','FN','R','SN', 'U','V'
 * Revision 1.1: Attention aux objets encryptés, la méthode Script() n'est pas invocable.
 */</span>
 <span style="color: #0000ff;">static bool scriptThis(int _objid, string _type, Database _curdb)
 {
     switch (_type)
     {

         case "P":   <span style="color: #008000;">// PROCEDURES STOCKEES -----------------------------------------------------</span>
             StoredProcedure _sp = _curdb.StoredProcedures.ItemById(_objid);

             if (_sp.IsEncrypted == false)
             {
                 StringCollection _spscr = _curdb.StoredProcedures.ItemById(_objid).Script();
                 foreach (string _line in _spscr)
                     Console.WriteLine(_line);
             }
             Console.WriteLine("GO");
             break;

         case "FN":  <span style="color: #008000;">// UDF ----------------------------------------------------------------------</span>
             UserDefinedFunction _f = _curdb.UserDefinedFunctions.ItemById(_objid);
             if (_f.IsEncrypted == false)
             {
                 StringCollection _fscr = _f.Script();
                 foreach (string _line in _fscr)
                     Console.WriteLine(_line);
             }
             Console.WriteLine("GO");
             break;

         case "R":   <span style="color: #008000;">// RULES -------------------------------------------------------------------</span>
              StringCollection _ruscr = _curdb.Rules.ItemById(_objid).Script();
              foreach (string _line in _ruscr)
                  Console.WriteLine(_line);
              Console.WriteLine("GO");
              break;

         case "SN":  <span style="color: #008000;">// SYNONYMS -----------------------------------------------------------------</span>
             StringCollection _synscr = _curdb.Synonyms.ItemById(_objid).Script();
             foreach (string _line in _synscr)
                 Console.WriteLine(_line);
             Console.WriteLine("GO");
             break;

         case "U":   <span style="color: #008000;">// TABLES UTILISATEUR + CONTRAINTES + TRIGGERS + INDEXES -------------------</span>
             Table _t = _curdb.Tables.ItemById(_objid);
             StringCollection _tablescr = _curdb.Tables.ItemById(_objid).Script();

             foreach (string _line in _tablescr)
                 Console.WriteLine(_line);

             IndexCollection _indexes = _t.Indexes;
             foreach (Index _i in _indexes)
             {
                 StringCollection _iscr = _i.Script();
                 foreach (string _line in _iscr)
                     Console.WriteLine(_line);
             }

             CheckCollection _checks = _t.Checks;
             foreach (Check _c in _checks)
             {
                 StringCollection _cscr = _c.Script();
                 foreach (string _line in _cscr)
                     Console.WriteLine(_line);
             }

             TriggerCollection _triggers = _t.Triggers;
             foreach (Trigger _trg in _triggers)
             {
                 StringCollection _trgscr = _trg.Script();
                 foreach (string _line in _trgscr)
                     Console.WriteLine(_line);
             }

             <span style="color: #008000;">// Pour les contraintes par défaut c'est un peu différent, il faut
             // passer par chaque colonne de la table, et faire attention si la
             // colonne ne contient pas de contrainte par défaut ( != null)</span>
             foreach (Column _col in _t.Columns)
             {
                 if (_col.DefaultConstraint != null)
                 {
                     StringCollection _def = _col.DefaultConstraint.Script();
                     foreach (string _line in _def)
                         Console.WriteLine(_line);
                 }
             }

             Console.WriteLine("GO");
             break;

        case "V":   <span style="color: #008000;">// VUES UTILISATEUR -----------------------------------------------------</span>
             View _v = _curdb.Views.ItemById(_objid);
             if (_v.IsEncrypted == false)
             {
                  StringCollection _vscr = _v.Script();
                  foreach (string _line in _vscr)
                      Console.WriteLine(_line);
             }
             Console.WriteLine("GO");
             break;

       default:
            Console.WriteLine("Objet {0} non supporté.", _type);
            break;
     }

 return true;

 }</span>
</pre>
<p>L&#8217;objet est récupéré en passant son object_id à la méthode <em>ItemById()</em> à chaque fois. Et en fonction du type, on applique la méthode correspondante avec le principe expliqué au début de cet article. Lorsque le thread a terminé la génération, il retourne bloquer à nouveau sur le kernel object pour lire la ligne suivante. On remarquera le filtrage avec <em>isEncrypted </em>pour les procédures, les fonctions et les vues.</p>
<h2>Conclusion:</h2>
<p>Au final, le gain de passer en multithread est de plus de 30% rien que sur mon laptop avec 2 threads au lieu d&#8217;un seul. En plus en activant PARAMETERIZATION = FORCED, le temps de génération pour AdventureWorks tombe de 1 minute 30 à 20 secondes. A la prochaine !</p>
<p>David B.</p>
<p><script src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO" type="text/javascript"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/" rel="bookmark" title="15 juillet 2010">Attention aux requêtes en double avec Windev et MySQL !</a> (Cédric PEINTRE) [MySQL]</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>
<li><a href="http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
</ul>
<p><!-- Similar Posts took 3.570 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%2Fgenerer-le-ddl-complet-dune-base-en-csmo%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fgenerer-le-ddl-complet-dune-base-en-csmo%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/XxIcbR1VV-U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/generer-le-ddl-complet-dune-base-en-csmo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/generer-le-ddl-complet-dune-base-en-csmo/</feedburner:origLink></item>
		<item>
		<title>Attention aux requêtes en double avec Windev et MySQL !</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/MZo3EN4-9bM/</link>
		<comments>http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 08:43:16 +0000</pubDate>
		<dc:creator>Cédric PEINTRE</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[HExécuteRequêteSQL]]></category>
		<category><![CDATA[HLitPremier]]></category>
		<category><![CDATA[hSansRafraichir]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[windev]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1094</guid>
		<description><![CDATA[Hello,
Un post pour vous démontrer que c&#8217;est toujours intéressant de lire les documentations et que parfois, les petites lignes en bas de page peuvent révéler des informations importantes.
J&#8217;étais récemment chez un client pour un audit de performance dans un environnement Windev / MySQL.
Je ne suis pas un grand spécialiste de Windev, bien qu&#8217;ayant déjà réalisé [...]]]></description>
			<content:encoded><![CDATA[<p>Hello,</p>
<p>Un post pour vous démontrer que c&#8217;est toujours intéressant de lire les documentations et que parfois, les petites lignes en bas de page peuvent révéler des informations importantes.</p>
<p>J&#8217;étais récemment chez un client pour un audit de performance dans un environnement Windev / MySQL.<br />
Je ne suis pas un grand spécialiste de Windev, bien qu&#8217;ayant déjà réalisé des audits sur ce type d&#8217;environnement, je n&#8217;avais jamais eu l&#8217;occasion d&#8217;aller aussi loin dans la compréhension du code applicatif.</p>
<p>Au hasard de l&#8217;analyse des requêtes lentes (via le log des requêtes lentes), je me suis aperçu qu&#8217;une requête apparaissait systématiquement deux fois consécutivement dans le log.</p>
<p>Après avoir identifié avec mon client le bout de code exécutant cette requête, nous avons travaillé avec le log général de MySQL afin d&#8217;essayer de comprendre pourquoi cette requête était lancée deux fois alors qu&#8217;elle n&#8217;apparaissait qu&#8217;une fois dans le code applicatif.</p>
<p><span style="text-decoration: underline;">Le code utilisé est le suivant :</span></p>
<p><em>SD</em> est une Source de Données<br />
<em>MaReq</em> est une chaîne</p>
<pre>####################################################################################</pre>
<pre>MaReq = "SELECT nom, prenom FROM client WHERE type =  1"</pre>
<pre>// Exécution de la requête</pre>
<pre>HExécuteRequêteSQL(SD,  MaConnexionMySQL,  hRequêteSansCorrection,  MaReq)</pre>
<p><strong> </strong></p>
<pre>// Boucle sur le résultat</pre>
<pre>HLitPremier(SD)</pre>
<pre>TANTQUE  PAS HEnDehors(SD)</pre>
<pre>Trace(SD.Nom)</pre>
<pre>HLitSuivant(SD)</pre>
<pre>FIN</pre>
<pre>####################################################################################</pre>
<p>Le verdict du log général est sans appel, la requête est bien exécutée deux fois !</p>
<p>Petite parenthèse, la fonction <em><strong>HExécuteRequêteSQL</strong></em> réalise systématiquement une modification de code SQL (Ajout d&#8217;un ORDER BY par exemple). Si vous souhaitez conserver votre code SQL original, n&#8217;oubliez pas d&#8217;ajouter le paramètre <em><strong>hRequêteSansCorrection</strong></em> comme fait ici.</p>
<p>Mais revenons à nos moutons, la mystérieuse requête en double&#8230;<br />
Après plusieurs tests, nous avons réussi à identifier la cause de cette double exécution, il s&#8217;agissait de la fonction <em><strong>HLitPremier</strong></em>.</p>
<p>En effet, cette fonction exécute une nouvelle fois la requête, certainement pour intégrer d&#8217;éventuelles modifications de données entre le moment où l&#8217;on exécute la requête et le moment où l&#8217;on entre dans la boucle.<br />
Simplement, si la requête est déjà coûteuse, elle l&#8217;est d&#8217;autant plus si elle est lancée deux fois et la seconde exécution n&#8217;est pas forcement nécessaire.<br />
Cela dépend évidemment du contexte applicatif dans lequel vous vous trouvez. Dans le cas présent, ce n&#8217;était pas nécessaire.</p>
<p>Nous voici donc en train d&#8217;éplucher la documentation Windev (c&#8217;est là que vous comprenez mon introduction) à la recherche d&#8217;une information capitale dans notre cas : Comment désactiver cette double exécution ?</p>
<p>Et nous n&#8217;avons pas mis longtemps (enfin, un peu quand même&#8230;) à repérer de petites lignes en bas de la page de la documentation de l&#8217;accès natif MySQL pour Windev :</p>
<p><strong>Optimisations des fonctions HyperFileSQL (Réf :  <a href="http://doc.pcsoft.fr/fr-FR/?acces-natif-mysql-pour-windev-webdev" target="_blank">http://doc.pcsoft.fr/fr-FR/?acces-natif-mysql-pour-windev-webdev</a>)</strong></p>
<ul>
<li><strong>L</strong>es Tables fichiers basées sur des requêtes sont optimisées : il    est possible de trier la table en cliquant sur une de ses colonnes.</li>
<li><strong>Pour éviter de ré-exécuter plusieurs fois la même requête lors du parcours    de son résultat, il est conseillé d&#8217;utiliser la constante </strong><em><strong>hSansRafraichir </strong></em><strong>(par exemple si un seul poste modifie les    données).</strong></li>
</ul>
<p>Donc, pour résumer, si vous utilisez la fonction <em>HLitPremier</em> et que vous ne souhaitez pas que celle-ci ré-exécute la requête précédemment exécutée par la fonction <em>HExécuteRequêteSQL</em>, vous devez utiliser la fonction avec le paramètre suivant :</p>
<ul>
<li>HLitPremier(SD,  <strong>hSansRafraîchir</strong>)</li>
</ul>
<p>Et effectivement, le log général ne mentionnait plus qu&#8217;une seule exécution après cette correction de code Windev !</p>
<p>J&#8217;espère que cette information vous sera utile pour vos devs Windev existants ou à venir. N&#8217;hésitez pas à nous faire un retour si vous aviez déjà rencontré ce problème ou pour tout retour d&#8217;expérience Windev / MySQL.</p>
<p>Un grand merci à toute l&#8217;équipe qui se reconnaitra et à bientôt sur le blog de capdata.<br />
Cédric</p>
<p>Documentation sur le log des requêtes lentes : <a href="http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html<br />
</a>Documentation sur le log général :  <a href="http://dev.mysql.com/doc/refman/5.1/en/query-log.html" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/query-log.html<br />
</a>Documentation Windev : <a href="http://doc.pcsoft.fr/fr-FR/" target="_blank">http://doc.pcsoft.fr/fr-FR/</a><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/sql-server-regles-dinstallation-de-base-episode-1/" rel="bookmark" title="18 juin 2009">Règles d&#8217;installation de base (épisode 1)</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/" rel="bookmark" title="30 mars 2010">Un trigger fait-il parti d&#8217;une transaction ?</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</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.734 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%2Fattention-aux-requetes-en-double-avec-windev-et-mysql%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fattention-aux-requetes-en-double-avec-windev-et-mysql%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/MZo3EN4-9bM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/</feedburner:origLink></item>
		<item>
		<title>Abonnez-vous au blog de la CapData team !</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/Kpg-FiigG0E/</link>
		<comments>http://blog.capdata.fr/index.php/abonnez-vous-au-blog-de-la-capdata-team/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 11:48:49 +0000</pubDate>
		<dc:creator>Cédric PEINTRE</dc:creator>
				<category><![CDATA[Général]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Sybase]]></category>
		<category><![CDATA[capdata]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1080</guid>
		<description><![CDATA[Bonjour à tous,
Juste un petit post pour vous rappeler les différentes méthodes vous permettant de suivre l&#8217;activité débordante du blog de la capdata team :

Accès standard via la page web : http://blog.capdata.fr
Vous abonner au flux RSS du blog et être ainsi prévenu de l&#8217;arrivée des nouveaux articles : http://feeds.feedburner.com/CapDataTeamBlog
Nous suivre sur Twitter pour retrouver l&#8217;actualité [...]]]></description>
			<content:encoded><![CDATA[<p>Bonjour à tous,</p>
<p>Juste un petit post pour vous rappeler les différentes méthodes vous permettant de suivre l&#8217;activité débordante du blog de la capdata team :</p>
<ul>
<li>Accès standard via la page web : <a href="http://blog.capdata.fr" target="_blank">http://blog.capdata.fr</a></li>
<li>Vous abonner au flux RSS du blog et être ainsi prévenu de l&#8217;arrivée des nouveaux articles : <a href="http://feeds.feedburner.com/CapDataTeamBlog" target="_blank">http://feeds.feedburner.com/CapDataTeamBlog</a></li>
<li>Nous suivre sur Twitter pour retrouver l&#8217;actualité des bases de données : <a href="http://twitter.com/capdata_blog" target="_blank">http://twitter.com/capdata_blog</a></li>
</ul>
<p>Vous êtes de plus en plus nombreux à nous suivre sur ce blog technique autour des bases de données et nous vous en remercions.</p>
<p>J&#8217;en profite pour vous proposer quelques articles qui semblent avoir remportés un vif succès dernièrement :</p>
<ul>
<li><a href="http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/" target="_self">http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/</a></li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/" target="_self">http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/</a></li>
<li><a href="http://blog.capdata.fr/index.php/modifier-la-collation-dune-base-sql-2005/" target="_self">http://blog.capdata.fr/index.php/modifier-la-collation-dune-base-sql-2005/</a></li>
<li><a href="http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/" target="_self">http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/</a></li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-direct-io-dsync-onoff-raw-device/" target="_self">http://blog.capdata.fr/index.php/sybase-ase-direct-io-dsync-onoff-raw-device/</a></li>
</ul>
<p>Encore une fois, n&#8217;hésitez pas à poster vos commentaires sur les articles, l&#8217;échange est la richesse du contenu.</p>
<p>A bientôt sur le blog de la capdata team !<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<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/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>
<li><a href="http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
<li><a href="http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/" rel="bookmark" title="13 juin 2008">Modes de récupération et journal de transactions, épisode 1</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.775 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%2Fabonnez-vous-au-blog-de-la-capdata-team%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fabonnez-vous-au-blog-de-la-capdata-team%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/Kpg-FiigG0E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/abonnez-vous-au-blog-de-la-capdata-team/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/abonnez-vous-au-blog-de-la-capdata-team/</feedburner:origLink></item>
		<item>
		<title>Réunion GUSS le 1er juillet !</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/vtBavOVoA6g/</link>
		<comments>http://blog.capdata.fr/index.php/reunion-guss-le-1er-juillet/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 06:54:14 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[GUSS]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=1068</guid>
		<description><![CDATA[Beaucoup de travail et pas beaucoup de temps pour écrire des articles. De nouveaux sujets vont arriver cependant, certainement durant l&#8217;été. Patience donc !
Bref un court post pour dire que je serai présent à la prochaine réunion du GUSS le 1er juillet. La réunion a lieu dans les nouveaux locaux de MS à Issy-les-Moulineaux, de [...]]]></description>
			<content:encoded><![CDATA[<p>Beaucoup de travail et pas beaucoup de temps pour écrire des articles. De nouveaux sujets vont arriver cependant, certainement durant l&#8217;été. Patience donc !</p>
<p>Bref un court post pour dire que je serai présent à la prochaine réunion du <a href="http://guss.fr/">GUSS</a> le 1er juillet. La réunion a lieu dans les nouveaux locaux de MS à Issy-les-Moulineaux, de 14h à 18h. Rudi Bruchez et Frédéric Brouard y feront une présentation chacun, ainsi qu&#8217;une personne de Quest.</p>
<p>Il n&#8217;est pas trop tard pour vous <a href="http://www.guss.fr/inscription.aspx">inscrire</a>. On espère vous y voir aussi !</p>
<p>A+ 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/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/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/" rel="bookmark" title="15 juillet 2010">Attention aux requêtes en double avec Windev et MySQL !</a> (Cédric PEINTRE) [MySQL]</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.814 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%2Freunion-guss-le-1er-juillet%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Freunion-guss-le-1er-juillet%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/vtBavOVoA6g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/reunion-guss-le-1er-juillet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/reunion-guss-le-1er-juillet/</feedburner:origLink></item>
		<item>
		<title>SQLDIAG (épisode 2)</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/D27LNcjVCGs/</link>
		<comments>http://blog.capdata.fr/index.php/sqldiag-episode-2/#comments</comments>
		<pubDate>Mon, 10 May 2010 16:28:36 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[perfmon]]></category>
		<category><![CDATA[readtrace]]></category>
		<category><![CDATA[RML Utilities]]></category>
		<category><![CDATA[sqldiag]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=985</guid>
		<description><![CDATA[Deuxième épisode de la trilogie sur SQLDIAG et les outils avancés de diagnostic autour de SQL Server. Nous parlerons aujourd&#8217;hui du résultat de la trace lancée lors du rapport précédent et de son contenu. Nous verrons comment charger le contenu de la trace SQL et du fichier BLG dans SQL Profiler pour interprétation. Puis nous [...]]]></description>
			<content:encoded><![CDATA[<p>Deuxième épisode de la trilogie sur SQLDIAG et les outils avancés de diagnostic autour de SQL Server. Nous parlerons aujourd&#8217;hui du résultat de la trace lancée lors du <a title="SQLDIAG episode 1" href="http://blog.capdata.fr/index.php/sqldiag-episode-1/">rapport précédent</a> et de son contenu. Nous verrons comment charger le contenu de la trace SQL et du fichier BLG dans SQL Profiler pour interprétation. Puis nous verrons comment mettre en place RML Utilities pour agréger et afficher le résultat d&#8217;une trace SQLDIAG.</p>
<h2>Contenu d&#8217;une trace SQLDIAG:</h2>
<p>Une fois la trace terminée, Ctrl-C stoppe le collecteur et commence à écrire les fichiers résultats sous l&#8217;arborescence. On retrouve une arborescence telle que:</p>
<pre><span style="color: #0000ff;">&lt;NOM TRACE&gt;
|___ log_*.trc
|___ MS2K8-WIN2008-1__sp_sqldiag_Shutdown.OUT
|___ MS2K8-WIN2008-1_MSINFO32.txt
|___ MS2K8-WIN2008-1_SQLDIAG__sp_trace_*.trc
|___ SQLDIAG.lbg
|___ internal
     |___ *.txt
     |___ *.OUT
</span></pre>
<ul>
<li><strong>log*.trc</strong>: ces fichiers contiennent la trace par défaut de l&#8217;instance. Ils ont été copiés de leur répertoire origine (le plus souvent ~MSSQL\LOG). Cf note bas de page dans le <a title="SQLDIAG  episode 1" href="http://blog.capdata.fr/index.php/sqldiag-episode-1/">premier article</a>.</li>
</ul>
<ul>
<li><strong>MS2K8-WIN29008-1__sp_sqldiag_Shutdown.OUT</strong>: ce fichier est divisé en plusieurs parties. Il n&#8217;est généré qu&#8217;au moment du Crtrl-C pour ne pas rater d&#8217;évènements survenus pendant la trace. Il commence par contenir le contenu de chaque fichier ERRORLOG*, puis la configuration de l&#8217;instance, la liste des processus (sp_who), la liste des verrous (sp_lock), la liste des bases (sp_helpdb), des informations sur le binaire (xp_msver), donne la liste de toutes les procédures stockées étendues déclarées (sp_helpextendedproc) , et le contenu de sysprocesses, sys.dm_exec_sessions, ::fn_virtualservernodes() si sur cluster, sysdevices, sysdatabases, sys.master_files. Enfin, la liste des requêtes en cours d&#8217;exécution. Le reste , où chaque vue sys.dm_os* est récupérée, est plus à destination du support pour diagnostic. Celà leur donne une image précise de l&#8217;activité au niveau des schedulers (SQLOS), de la mémoire, des latches, des modules chargés dans l&#8217;espace d&#8217;adressage de sqlservr.exe, etc&#8230; C&#8217;est beaucoup plus pratique que de faire générer un dump ou un mini-dump au client qui rencontre un problème. D&#8217;ailleurs, il y aura certainement un article prochainement sur les vues sys.dm_os* principales, je ne m&#8217;étends donc pas dessus, car pour l&#8217;instant ce n&#8217;est pas ce qui nous intéresse.</li>
</ul>
<ul>
<li><strong>MS2K8-WIN29008-1_MSINFO32.txt</strong>: Contient le contenu au format texte de msinfo32. Toutes les informations systèmes sont contenues dans ce fichier, classées par section entre crochets ([]). Nombre d&#8217;entre elles sont sans intérêt (IRQ/DMA, périphériques, clavier, pilotes, etc&#8230;), il y cependant certaines sections qui valent le coup d&#8217;oeil: [System Summary] pour les informations systèmes courantes (OS, CPU, mémoire, etc&#8230;), [Drives] et [Disks] pour les disques, [Running Tasks] pour les processus en cours d&#8217;exécution, [Windows Error Reporting] pour les messages d&#8217;erreurs de l&#8217;eventvwr.</li>
</ul>
<ul>
<li><strong>MS2K8-WIN29008-1_SQLDIAG__sp_trace_*.trc</strong>: ces fichiers contiennent la trace SQL Trace que l&#8217;on a paramétrée dans le fichier XML.</li>
</ul>
<ul>
<li><strong>SQLDIAG.blg</strong>: ce fichier contient la trace système paramétrée dans le fichier XML.</li>
</ul>
<ul>
<li><strong>~internal\</strong>: ce sous répertoire contient les logs de l&#8217;exécution de SQLDIAG. En fonction de la version utilisée, les fichiers OUT et txt peuvent se trouver au même niveau que les fichiers résultats.</li>
</ul>
<p>Les deux axes qui vont nous intéresser sont principalement les fichiers de trace SQL et le fichier BLG. Les autres fichiers seront plus à utiliser à des fins de diagnostic.</p>
<h2><strong>Charger une trace SQL et un fichier BLG dans SQL Profiler:</strong></h2>
<p>Il est possible de charger un fichier de compteurs perfmon et une trace SQL dans SQL Profiler pour corrélation. Ce n&#8217;est possible toutefois que si les deux traces ont été générées ensembles, le plus souvent à l&#8217;aide d&#8217;un outil comme SQLDIAG ou PSSDIAG. Tout d&#8217;abord, ouvrir la trace SQL dans Profiler, puis <em>File-&gt;Import Performance Data&#8230;</em> Sélectionner le fichier BLG généré dans la même trace, puis les compteurs à charger (pour plus de lisibilité, on ne prendra que les compteurs disque dans notre cas), et importer la trace:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/05/SQLDIAG11.jpg"><img class="alignnone size-full wp-image-1025" title="SQLDIAG1" src="http://blog.capdata.fr/wp-content/uploads/2010/05/SQLDIAG11.jpg" alt="" width="516" height="480" /></a></p>
<p>L&#8217;écran se divise en quatre parties. Les zones extrêmes représentent l&#8217;affichage classique de SQL Profiler: texte et statistiques des requêtes. La partie centrale présente les graphes associés aux compteurs du fichier BLG, et la partie inférieure la liste des compteurs avec les valeurs Min, Max, Average:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/05/SQLDIAG21.jpg"><img class="alignnone size-large wp-image-995" title="SQLDIAG2" src="http://blog.capdata.fr/wp-content/uploads/2010/05/SQLDIAG21-1024x703.jpg" alt="" width="1024" height="703" /></a></p>
<p>Il est possible de zoomer et de déplacer le curseur temporel dans la partie centrale, et Profiler va pointer sur les requêtes exécutées à l&#8217;instant sélectionné, et la valeur de &#8216;<em>Selected</em>&#8216; dans la partie inférieure est également mise à jour pour chaque compteur.</p>
<p>Maintenant il faut bien faire attention à ce que l&#8217;on lit ou ce que l&#8217;on interprète. Il faut bien se rendre compte que SQL Trace collecte les statistiques pour un évènement une fois qu&#8217;il s&#8217;est terminé, donc ce n&#8217;est pas parce qu&#8217;on va pointer sur un pic CPU ou un de temps de service disque  qu&#8217;on va tomber pile sur le problème. On va dire que ça facilite la tâche, ça permet de corréler des informations, mais ça ne fait pas le travail à votre place. Une requête peut commencer à faire des lectures physiques depuis le disque pendant une minute, puis faire d&#8217;autres opérations en mémoire (des tris, des agrégations) et se terminer un certain temps  après le pic. Un petit exemple d&#8217;une requête qui fait des accès physiques pendant 1 minute et qui se termine à la fin du pic. Si on ne regarde pas bien, on rate l&#8217;information:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/05/SQLDIAG3.jpg"><img class="alignnone size-large wp-image-997" title="SQLDIAG3" src="http://blog.capdata.fr/wp-content/uploads/2010/05/SQLDIAG3-1024x460.jpg" alt="" width="1024" height="460" /></a></p>
<h2>RML Utilities:</h2>
<p>RML Utilities est une petite application due, comme pas mal d&#8217;outils et d&#8217;avancées sur le moteur, à l&#8217;initiative de l&#8217;équipe <a title="MS PSS" href="http://blogs.msdn.com/psssql">Customer Support Services</a>. La première version de RML s&#8217;appuyait sur deux binaires <a title="KB1" href="http://support.microsoft.com/kb/887057">Ostress et ReadTrace</a> principalement, elle a été refondue en 2007 pour incorporer une petite application d&#8217;affichage des traces, basée sur des reports RDL. Les versions x86 et x64 sont téléchargeables depuis <a href="http://blogs.msdn.com/psssql/archive/2007/12/18/rml-utilities-for-microsoft-sql-server-released.aspx">la page d&#8217;accueil de RML</a>. L&#8217;installation n&#8217;a rien de compliqué, donc on va passer directement à la phase d&#8217;intégration des traces.</p>
<p>Cette intégration se fait avec ReadTrace. Tout d&#8217;abord, on va créer une base pour stocker les données des traces:</p>
<pre><span style="color: #0000ff;">create database RMLDB</span></pre>
<p>Puis ReadTrace avec les options -I&lt;chemin vers fichier trc initial&gt; -S&lt;instance&gt; -d&lt;Baserepository&gt; (important de ne pas laisser d&#8217;espace entre le commutateur et le paramètre)</p>
<pre><span style="color: #888888;"><span style="color: #0000ff;">$ ./ReadTrace -IE:/SQLDIAG/TRACE3/SQL2008__sp_trace.trc -SMS2K8-Win2008-1 -E -dRMLDB</span>

<em>05/10/10 17:13:20.920 [0X000013B4] Output path was not specified; defaulting to C:\Users\capdata\AppData\Local\Temp\2\\output
05/10/10 17:13:21.000 [0X000013B4] Readtrace a SQL Server trace processing utility.
Version 9.01.0109 built for x86.
Copyright (c) Microsoft Corporation 1997-2008. All rights reserved.
05/10/10 17:13:21.002 [0X000013B4] Number of processors: 1
05/10/10 17:13:21.002 [0X000013B4]     Active proc mask: 0x00000001
05/10/10 17:13:21.008 [0X000013B4]         Architecture: 0
05/10/10 17:13:21.009 [0X000013B4]            Page size: 4096
05/10/10 17:13:21.009 [0X000013B4]         Highest node: 0
05/10/10 17:13:21.010 [0X000013B4]         Package mask: 0x00000001
05/10/10 17:13:21.011 [0X000013B4]         Processor(s): 0x00000001 Function units: Separated
05/10/10 17:13:21.011 [0X000013B4]           Processors: 0x00000001 assigned to Numa node: 0
05/10/10 17:13:21.012 [0X000013B4] -IE:/SQLDIAG/TRACE3/SQL2008__sp_trace.trc
05/10/10 17:13:21.012 [0X000013B4] -SMS2K8-Win2008-1
05/10/10 17:13:21.013 [0X000013B4] -E
05/10/10 17:13:21.013 [0X000013B4] -dRMLDB
05/10/10 17:13:21.014 [0X000013B4] Using language id (LCID): 1024 [French_France.1252] for character formatting with NLS: 0x00500100 and Defined: 0x00050100
05/10/10 17:13:21.015 [0X000013B4] Attempting to cleanup existing RML files from previous execution
05/10/10 17:13:21.016 [0X000013B4] Using extended RowsetFastload synchronization
05/10/10 17:13:21.017 [0X000013B4] Establishing initial database connection:
05/10/10 17:13:21.017 [0X000013B4] Server: MS2K8-Win2008-1
05/10/10 17:13:21.018 [0X000013B4] Database: RMLDB
05/10/10 17:13:21.018 [0X000013B4] Authentication: Windows
05/10/10 17:13:21.470 [0X000013B4] Using SQL Client version 10
05/10/10 17:13:21.471 [0X000013B4] Creating or clearing the performance database
05/10/10 17:13:22.916 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace.trc (SQL 2005)
05/10/10 17:13:22.918 [0X000013B4] Validating core events exist
05/10/10 17:13:22.919 [0X000013B4] Validating necessary events exist for analysis
05/10/10 17:13:22.921 [0X000013B4] Validating necessary events exist for RML breakout
05/10/10 17:13:22.922 [0X000013B4] WARNING: Event [Server: Server Memory Change] missing from trace
05/10/10 17:13:22.923 [0X000013B4] WARNING REPLAY: The following trace events were not captured: [Sessions:ExistingConnection, Security Audit: Audit Login, Se
rity Audit: Audit Logout, Stored Procedures: RPC Output Parameter, Cursors:Unprepare, Cursors:CursorClose, Cursors:CursorPrepare, Cursors:CursorCreated, Curso
:CursorExecute, TSQL: Prepare SQL, TSQL: Unprepare SQL, Errors and Warnings:Attention, Transactions:SQLTransaction, Transactions:DTCTransaction, Transactions:
:Begin Tran starting and completed, Transactions:TM:Commit Tran starting and completed, Transactions:TM:Rollback Tran starting and completed, Transactions:TM:
ve Tran starting and completed, Transactions:TM:Promote Tran starting and completed, SQL:BatchStarting and SQL:BatchCompleted, RPC:Starting and RPC:Completed]
Review the help file to ensure that you have collected the appropriate set of events and columns for RML replay needs.  Lack of these events can lead to sever
replay problems.

Trace flag -T28 disables the check allowing RML output processing. *** Use with caution as the output and behavior could be unpredictable.
05/10/10 17:13:22.993 [0X000013B4] Events Read: 1000 Queued: 1000 Processed/sec: 0
05/10/10 17:13:23.026 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_1.trc (SQL 2005)
05/10/10 17:13:23.038 [0X000013B4] Events Read: 2000 Queued: 2000 Processed/sec: 0
05/10/10 17:13:23.070 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_2.trc (SQL 2005)
05/10/10 17:13:23.082 [0X000013B4] Events Read: 3000 Queued: 3000 Processed/sec: 0
05/10/10 17:13:23.261 [0X000013B4] Events Read: 4000 Queued: 4000 Processed/sec: 0
05/10/10 17:13:23.271 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_3.trc (SQL 2005)
05/10/10 17:13:23.284 [0X000013B4] Events Read: 5000 Queued: 5000 Processed/sec: 0
05/10/10 17:13:23.328 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_4.trc (SQL 2005)
05/10/10 17:13:23.342 [0X000013B4] Events Read: 6000 Queued: 6000 Processed/sec: 0
05/10/10 17:13:23.361 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_5.trc (SQL 2005)
05/10/10 17:13:23.366 [0X000013B4] Events Read: 7000 Queued: 7000 Processed/sec: 0
05/10/10 17:13:23.396 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_6.trc (SQL 2005)
05/10/10 17:13:23.406 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_7.trc (SQL 2005)
05/10/10 17:13:23.475 [0X000013B4] Events Read: 8000 Queued: 8000 Processed/sec: 0
05/10/10 17:13:23.574 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_8.trc (SQL 2005)
05/10/10 17:13:24.175 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_9.trc (SQL 2005)
05/10/10 17:13:24.313 [0X000013B4] Events Read: 9000 Queued: 8998 Processed/sec: 2
05/10/10 17:13:24.854 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_10.trc (SQL 2005)
05/10/10 17:13:24.905 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_11.trc (SQL 2005)
05/10/10 17:13:24.939 [0X000013B4] Processing file: E:\SQLDIAG\TRACE3\SQL2008__sp_trace_12.trc (SQL 2005)
05/10/10 17:13:24.959 [0X000013B4] Found TRACE_STOP with 0 bytes of data
05/10/10 17:13:24.961 [0X000013B4] Found [TRACE_STOP] event indicating the end of the trace files.
05/10/10 17:13:24.962 [0X000013B4] Reads completed
05/10/10 17:13:24.965 [0X000013B4] Shutting down the worker thread message queues.
05/10/10 17:13:24.996 [0X000013B4] Waiting for the worker threads to complete final actions.
05/10/10 17:13:26.074 [0X000013B4] Performing general cleanup actions.
05/10/10 17:13:26.076 [0X000013B4] Reducing cached memory.
05/10/10 17:13:26.096 [0X000013B4] Total Events Processed: 11117
05/10/10 17:13:26.101 [0X000013B4]  Total Events Filtered: 0
05/10/10 17:13:26.102 [0X000013B4] Parse errors: 0
05/10/10 17:13:26.224 [0X000013B4] Table ReadTrace.tblUniqueBatches: loaded ~445 rows
05/10/10 17:13:26.225 [0X000013B4] Table ReadTrace.tblUniqueStatements: loaded ~0 rows
05/10/10 17:13:26.225 [0X000013B4] Table ReadTrace.tblUniquePlans: loaded ~0 rows
05/10/10 17:13:26.226 [0X000013B4] Table ReadTrace.tblUniquePlanRows: loaded ~0 rows
05/10/10 17:13:26.241 [0X000013B4] Table ReadTrace.tblBatches: loaded ~4355 rows
05/10/10 17:13:26.242 [0X000013B4] Table ReadTrace.tblStatements: loaded ~0 rows
05/10/10 17:13:26.243 [0X000013B4] Table ReadTrace.tblPlans: loaded ~0 rows
05/10/10 17:13:26.244 [0X000013B4] Table ReadTrace.tblPlanRows: loaded ~0 rows
05/10/10 17:13:26.257 [0X000013B4] Table ReadTrace.tblInterestingEvents: loaded ~3 rows
05/10/10 17:13:26.258 [0X000013B4] Table ReadTrace.tblConnections: loaded ~0 rows
05/10/10 17:13:26.262 [0X000013B4] WARNING: One or more warning conditions exist that may affect the quality of the analysis data.  See RMLDB.ReadTrace.tblWar
ngs table and the ReadTrace log for complete details.
05/10/10 17:13:26.269 [0X000013B4] Indexing tables...
05/10/10 17:13:27.413 [0X000013B4] Doing post-load data cleanup...
05/10/10 17:13:27.863 [0X000013B4] Computing partial aggregates...
05/10/10 17:13:28.977 [0X000013B4] Data load completed.
05/10/10 17:13:28.979 [0X000013B4] Using execution path: c:\Program Files\Microsoft Corporation\RMLUtils
05/10/10 17:13:28.980 [0X000013B4] Launching [c:\Program Files\Microsoft Corporation\RMLUtils\Reporter.exe]
05/10/10 17:13:29.253 [0X000013B4] *******************************************************************************
* ReadTrace encountered one or more WARNINGS. A warning condition typically   *
* continues processing with reduced functionality, but the ReadTrace output   *
* may be adversely affected. Review the log file for details.                 *
*******************************************************************************
05/10/10 17:13:29.324 [0X000013B4]
</em></span><span style="color: #888888;"> </span></pre>
<p>Les deux warnings indiquent juste qu&#8217;il va manquer certains évènements, notamment les évènements pour pouvoir faire un replay dans Profiler.  A la fin du chargement, l&#8217;application &#8216;<em>Reporter</em>&#8216; est lancée et permet de visualiser les informations de la trace:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/05/RML1.jpg"><img class="alignnone size-full wp-image-1018" title="RML1" src="http://blog.capdata.fr/wp-content/uploads/2010/05/RML1.jpg" alt="" width="986" height="710" /></a></p>
<p>Ensuite, il est assez simple de naviguer dans l&#8217;interface et de visualiser l&#8217;information agrégée, par exemple en cliquant sur &#8216;<em>Unique Batches&#8217;</em>:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/05/RML2.jpg"><img class="alignnone size-full wp-image-1019" title="RML2" src="http://blog.capdata.fr/wp-content/uploads/2010/05/RML2.jpg" alt="" width="989" height="703" /></a></p>
<p>&#8230; et de repérer les requêtes consommatrices par critère (coût CPU, I/Os, durée), et visualiser le plan (si pris dans la trace):</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/05/RML4.jpg"><img class="alignnone size-full wp-image-1021" title="RML4" src="http://blog.capdata.fr/wp-content/uploads/2010/05/RML4.jpg" alt="" width="918" height="351" /></a></p>
<p>Dernier épisode, on verra OSTRESS et ORCA, et les alternatives à SQLDIAG+RML Utilites: PSSDIAG, SQL Nexus, SQLH2, Data Collector, les reports SSMS.</p>
<p>A+ David B. (avec la collaboration de Martial LUCAS. )</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 2180px; width: 1px; height: 1px;">lrwxrwxrwx 1 root root 4 2008-07-09 12:41 /bin/sh -&gt; bash</p>
</div>
<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>
</ul>
<p><!-- Similar Posts took 1.452 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%2Fsqldiag-episode-2%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsqldiag-episode-2%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/D27LNcjVCGs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sqldiag-episode-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sqldiag-episode-2/</feedburner:origLink></item>
		<item>
		<title>Jeux de caractères, Unicode  et Base de données</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/7Ys5YyHTBXA/</link>
		<comments>http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/#comments</comments>
		<pubDate>Fri, 23 Apr 2010 10:31:37 +0000</pubDate>
		<dc:creator>Guillaume DEFENDINI</dc:creator>
				<category><![CDATA[Général]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Sybase]]></category>
		<category><![CDATA[characterset]]></category>
		<category><![CDATA[jeux de caractères]]></category>
		<category><![CDATA[nchar]]></category>
		<category><![CDATA[nvarchar]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=961</guid>
		<description><![CDATA[Introduction
Un caractère est un symbole ou un signe unique appartenant à un alphabet.
Le jeu de caractères est un ensemble de caractères à représenter.
Il existe plusieurs jeux de caractères, permettant de représenter différents alphabets du monde.
Le standard ASCII
 
 
 
Afin de répertorier tous les caractères, un standard a été mis en place.
Le premier standard qui [...]]]></description>
			<content:encoded><![CDATA[<div><strong>Introduction</strong></div>
<div>Un caractère est un symbole ou un signe unique appartenant à un alphabet.</div>
<div>Le jeu de caractères est un ensemble de caractères à représenter.</div>
<div>Il existe plusieurs jeux de caractères, permettant de représenter différents alphabets du monde.</div>
<p><strong>Le standard ASCII</strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><span style="font-weight: normal;">Afin de répertorier tous les caractères, un standard a été mis en place.</span></p>
<p><span style="font-weight: normal;">Le premier standard qui voit le jour est l’ASCII. </span></p>
<p><span style="font-weight: normal;">Pour représenter des caractères dans un fichier texte, on associe un nombre (code) à une lettre, à un chiffre ou à un symbole.</span></p>
<p><span style="font-weight: normal;">L’encodage le plus connu de l’ASCII est US-ASCII. </span></p>
<p><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">A =&gt; 65 =&gt; 01000001</span></p>
<p><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">a =&gt; 97 =&gt; 01100001 </span></p>
<p><span style="font-weight: normal;">Le codage est réalisé sur 7bits/octet soit 128 symboles possibles. Une trentaine d&#8217;entre eux sont des caractères de commande, le reste est constitué de l&#8217;alphabet anglais standard, des chiffres et des ponctuations. </span></p>
<p><span style="font-weight: normal;">L’extension la plus connue est la famille ISO-8859, permettant de représenter les caractères accentués. Le codage est réalisé sur un octet complet, soit 256 caractères possibles. Les codes de 160 à 255 sont affectés au codage des caractères latins accentués.</span></p>
<p><span style="font-weight: normal;">Standards ISO-8859-1 à 15</span></p>
<p><span style="font-weight: normal;"> ISO-8859-1 puis 15 (euro): Europe de l&#8217;Ouest</span></p>
<p><span style="font-weight: normal;"> ISO-8859-2: Europe Centrale ou de l&#8217;Est</span></p>
<p><span style="font-weight: normal;"> ISO-8859-5: Cyrillique</span></p>
<p><span style="font-weight: normal;"> ISO-8859-7: Grec</span><span><span style="font-weight: normal;"> </span></span></p>
<p><span style="font-weight: normal;"><strong> </strong></span></p>
<p><strong> <span style="font-weight: normal;">Les principaux problèmes rencontrés avec ce standard sont les suivants :</span></strong></p>
<p>- On ne peut utiliser plusieurs langues à l&#8217;intérieur d&#8217;une même instance.</p>
<p><span style="font-weight: normal;">- Deux grands absents de l&#8217;ISO-Latin-1 sont la ligature oe « œ », essentielle à la typographie française correcte, et le symbole de l&#8217;euro « € ».</span></p>
<p><span style="font-weight: normal;">- Chaque constructeur d&#8217;ordinateur a aussi développé ses propres codes non conformes aux standards internationaux (IBM EBCDIC, Windows-1252,..) </span></p>
<p><strong>L’unicode</strong></p>
<p><span style="font-weight: normal;">La globalisation consiste à intégrer dans une même table tous les caractères connus du monde. </span></p>
<p><span style="font-weight: normal;">Le standard Unicode est un mécanisme universel de codage de caractères. Il définit une manière cohérente de coder des textes multilingues et facilite l’échange de données textuelles. </span></p>
<p><span style="font-weight: normal;">Il est un passage obligatoire pour la plupart des nouveaux protocoles de l’Internet, mis en œuvre dans tous les systèmes d’exploitation et langages informatiques modernes.</span></p>
<p><span style="font-weight: normal;"><span style="text-decoration: underline;">Formes de codage</span></span></p>
<p><span style="font-weight: normal;">Il existe plusieurs formes de codage de caractères pour l&#8217;Universal Character Set:</span></p>
<p><span style="font-weight: normal;">- UCS-2</span></p>
<p><span style="font-weight: normal;">- UCS-4</span></p>
<p>Cependant, les codages UCS-2 et UCS-4 sont difficiles à utiliser dans de nombreuses applications et protocoles qui travaillent avec des caractères codés sur 8 ou même 7 bits. Même certains systèmes plus récents capables de travailler avec des caractères sur 16 bits ne peuvent pas traiter les données codées en UCS-4. Cette situation a conduit au développement de formats de transformation UTF (UCS Transformation Formats). Chacun possédant ses propres caractéristiques.</p>
<p><span style="text-decoration: underline;">Encodage UTF 8</span></p>
<p><span style="font-weight: normal;">UTF-8 a été conçu par Kenneth Thompson en 1992 pour être compatible avec certains logiciels originellement prévus pour traiter des caractères d&#8217;un seul octet. </span></p>
<p><span style="font-weight: normal;">Les caractères de numéro 0 à 127 sont codés sur un octet dont le bit de poids fort est toujours nul.</span></p>
<p><span style="font-weight: normal;">Les caractères de numéro supérieur à 127 sont codés sur plusieurs octets.</span></p>
<p><span style="text-decoration: underline;">Encodage UTF 16</span></p>
<p><span style="font-weight: normal;">UTF-16 est une méthode permettant de transformer un sous-ensemble de la table UCS-4 en une paire de valeurs UCS-2 d’une plage réservée. </span></p>
<p><span style="font-weight: normal;">UTF-16 est décomposé en 2 types.</span></p>
<p><span style="font-weight: normal;">UTF-16-BE (Big-endian)</span></p>
<p><span style="font-weight: normal;">UTF-16-LE (Little-endian)</span></p>
<p><span style="font-weight: normal;">Le codage UTF-16-BE est l&#8217;un des codages préconisés par la norme Unicode. Ce codage associe simplement un code de 16 bits (2 octets) à chaque caractère.</span></p>
<p><span style="text-decoration: underline;">Encodage UTF 32</span></p>
<p><span style="font-weight: normal;">UTF-32 est un protocole pour encoder les caractères sur 32 bits. Du fait que l’UTF-32 utilise 4 bytes par caractère. </span></p>
<p><span style="font-weight: normal;">Il est aussi  décomposé en 2 types.</span></p>
<p><span style="font-weight: normal;">UTF-32-BE (Big-endian)</span></p>
<p><span style="font-weight: normal;">UTF-32-LE (Little-endian)</span></p>
<p><span style="font-weight: normal;">Il est relativement consommateur d’espace.</span></p>
<p><strong>Support SGBD</strong></p>
<p style="text-align: center;"><a href="http://blog.capdata.fr/wp-content/uploads/2010/04/unicode_sgbd.png"><img class="size-medium wp-image-962 aligncenter" src="http://blog.capdata.fr/wp-content/uploads/2010/04/unicode_sgbd-300x161.png" alt="" width="500" height="261" /></a></p>
<p><strong>Oracle</strong></p>
<p><span style="font-weight: normal;">Deux paramètres permettent de prendre en charge l’Unicode.</span></p>
<ul>
<li><span style="font-weight: normal;">Database Character Set</span></li>
<li><span style="font-weight: normal;">National Character Set</span></li>
</ul>
<p><span style="font-weight: normal;">Ces paramètres sont définis lors de la création de la base.</span></p>
<p><span style="font-weight: normal;">L’instruction CREATE DATABASE dispose de la clause character set et de la clause national character set qui permettent de déclarer le jeu de caractères qui servira de jeu de caractères de la base et de jeu de caractères nationaux. </span></p>
<p><span style="font-weight: normal;">Sans spécification de la clause national character set, le jeu AL16UTF16 sera utilisé par défaut.</span></p>
<p><span style="font-weight: normal;">Le paramètre Database Character Set ne peut pas être configuré en UTF-16.</span></p>
<p><span style="font-weight: normal;">Oracle gère l&#8217;unicode au niveau des colonnes grâce </span>National Character Set et <span style="font-weight: normal;">au types de données suivantes :</span></p>
<ul>
<li><span style="font-weight: normal;">Nchar</span></li>
<li><span style="font-weight: normal;">Nvarchar2</span></li>
<li><span style="font-weight: normal;">nclob</span></li>
</ul>
<p><strong>Sybase</strong></p>
<p><span style="font-weight: normal;">Au moment de l’installation, vous devez définir le paramètre default character set. Par défaut il est déterminé par celui utilisé sur votre server (Win = 1252, solaris =ISO 8859-1). Sybase recommande de définir UTF 8 pour ce paramètre si vous utiliser de l&#8217;unicode.</span></p>
<p><span style="font-weight: normal;">Sybase supporte la gestion de l’unicode au niveau du type de colonne à l’aide des 3 types suivants : </span></p>
<p><span style="font-weight: normal;">-</span><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">Unichar</span></p>
<p><span style="font-weight: normal;">-</span><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">Univarchar</span></p>
<p><span style="font-weight: normal;">-</span><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">Unitext</span></p>
<p><span style="font-weight: normal;">Ces 3 types de données sont encodés en UTF 16.</span></p>
<p><strong>Sql server</strong></p>
<p><span style="font-weight: normal;">Nous  allons introduire la notion de collation.</span></p>
<p><span style="font-weight: normal;"> Une collation est une table de correspondance spécifique à un jeu de caractères. </span></p>
<p><span style="font-weight: normal;">Un jeu de caractères peut avoir plusieurs collations, en général une par langue (par exemple, latin1 français, latin1 suédois). </span></p>
<p><span style="font-weight: normal;">Ce paramètre se définit à l&#8217;installation, sa valeur par défaut est en fonction de la langue de l&#8217;OS sur lequel se fait l&#8217;installation (pour les collations de type windows) : </span></p>
<p><span style="font-weight: normal;">Système en français : French_CI_AS </span></p>
<p><span style="font-weight: normal;">Système en anglais : Latin1_General_CI_AS </span></p>
<p><span style="font-weight: normal;">Il sert à déterminer la page de code utilisée dans les champs non unicode (varchar par exemple), l&#8217;ordre de tri des chaînes de caractère et aussi la sensibilité aux accents, aux majuscules, etc.</span></p>
<p><span style="font-weight: normal;">La collation paramétrée s&#8217;applique aux bases de données systèmes (master, msdb, tempdb et model) et par défaut aux nouvelles bases de données créées. Elle peut cependant être modifiée lors de la création d&#8217;une nouvelle base de données ou lors de l&#8217;ajout d&#8217;un champ texte grâce au mot clef COLLATE. </span></p>
<p>Sql server supporte la gestion de l’unicode à travers le type de colonne :</p>
<p><span style="font-weight: normal;">-</span><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">Nchar</span></p>
<p><span style="font-weight: normal;">-</span><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">Nvarchar</span></p>
<p><span style="font-weight: normal;">-</span><span><span style="font-weight: normal;"> </span></span><span style="font-weight: normal;">Ntext</span></p>
<p><strong>My sql</strong></p>
<p>MySQL détermine le jeu de caractères et la collation en fonction de l&#8217;option de configuration active quand le serveur démarre ou en fonction des valeurs de configuration à l&#8217;exécution.</p>
<p><span style="font-weight: normal;">Vous pouvez utiliser &#8211;default-character-set=character_set_name comme jeu de caractères et vous pouvez en même temps ajouter &#8211;default-collation=collation_name pour la collation. Par défaut mysql utilise les options suivante &#8211;default-charset=latin1 &#8211;collation=latin1_swedish_ci car latin1_swedish_ci est la collation par défaut de latin1.</span></p>
<p><span style="font-weight: normal;">La collation peut aussi être définie au niveau de la base ou de la colonne à l’aide de la clause collate.</span></p>
<p><span style="font-weight: normal;">En MySQL version 4.x et plus ancien, NCHAR et CHAR étaient synonymes. </span></p>
<p><span style="font-weight: normal;">MySQL utilise UTF8 comme jeu de caractère prédéfini pour les champs de types Nchar et Nvarchar .</span><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/" rel="bookmark" title="11 décembre 2008">Modes de récupération et journal de transactions, épisode 2</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/" rel="bookmark" title="13 juin 2008">Modes de récupération et journal de transactions, épisode 1</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</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>
</ul>
<p><!-- Similar Posts took 3.014 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%2Fjeux-de-caracteres-unicode-et-base-de-donnees%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fjeux-de-caracteres-unicode-et-base-de-donnees%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/7Ys5YyHTBXA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/</feedburner:origLink></item>
		<item>
		<title>Modifier PAGE_VERIFY après une migration depuis SQL 2000</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/oOqII1XwHTs/</link>
		<comments>http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 13:35:11 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[checksum]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[page_verify]]></category>
		<category><![CDATA[torn page detection]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=890</guid>
		<description><![CDATA[En regardant une session de Paul Randal sur les corruptions à la teched de Barcelone en 2008* , j&#8217;ai réalisé qu&#8217;il manquait une étape dans notre listing de choses à faire à la suite d&#8217;une migration de 2000 vers 2005 ou 2008.
Par défaut en version 2000, PAGE_VERIFY n&#8217;a qu&#8217;une seule valeur possible pour vérifier la [...]]]></description>
			<content:encoded><![CDATA[<p>En regardant une <a title="Paul Randal TechEd 2008" href="http://www.microsoft.com/emea/teched2008/itpro/tv/default.aspx?vid=78">session </a>de Paul Randal sur les corruptions à la teched de Barcelone en 2008* , j&#8217;ai réalisé qu&#8217;il manquait une étape dans notre listing de choses à faire à la suite d&#8217;une migration de 2000 vers 2005 ou 2008.</p>
<p>Par défaut en version 2000, PAGE_VERIFY n&#8217;a qu&#8217;une seule valeur possible pour vérifier la consistance des pages sur disque, TORN_PAGE_DETECTION.  TPD propose un mécanisme de vérification lorsque l&#8217;écriture d&#8217;une page ne peut pas se faire en entier, en raison d&#8217;une coupure d&#8217;alimentation par exemple ou tout autre problème entre SQL Server et le disque. Mais le scope de détection était limité car seuls les 2 premiers bits de chacun des 16 secteurs de 512 octets d&#8217;une page étaient scrutés pour calculer une séquence de contrôle (<em>m_tornBits</em> dans un dbcc page). Un écrasement de bits au milieu d&#8217;un secteur ne pouvait donc pas être détecté de cette manière.</p>
<p>A partir de la version 2005, une nouvelle valeur CHECKSUM est devenue option par défaut. Elle va calculer une somme de contrôle de l&#8217;intégralité de chaque page pour pouvoir détecter lorsque le contenu d&#8217;une page a été modifié même de manière infime. L&#8217;algorithme a été revu et implémenté de telle sorte qu&#8217;il n&#8217;impacte pas les performances (cf <a title="Linchea Shea's SQL Server Blog" href="http://sqlblog.com/blogs/linchi_shea/archive/2007/01/16/performance-impact-of-enabling-page-checksum-and-default-trace.aspx">post</a> Linchi Shea). Il est évidemment recommandé de laisser cette option PAGE_VERIFY sur CHECKSUM.</p>
<p>Le problème, c&#8217;est que PAGE_VERIFY, tout comme le mode de compatibilité de la base, n&#8217;est pas modifié lorsque la base migre de 2000 vers 2005 ou 2008:</p>
<pre><span style="color: #000080;">restore database pagechecksumtest from disk='F:\SQLDATA$SQL2000\BACKUP\pagechecksumtest.bak'
with move 'pagechecksumtest' to 'E:\SQLDATA$SQL2005\DATA\pagechecksumtest.mdf',
move 'pagechecksumtest_log' to 'F:\SQLDATA$SQL2005\LOG\pagechecksumtest_log.ldf',
stats</span></pre>
<pre><em>16 percent processed.
24 percent processed.
33 percent processed.
41 percent processed.
58 percent processed.
66 percent processed.
74 percent processed.
83 percent processed.
91 percent processed.
100 percent processed.
Processed 96 pages for database 'pagechecksumtest', file 'pagechecksumtest' on file 1.
Processed 1 pages for database 'pagechecksumtest', file 'pagechecksumtest_log' on file 1.
Converting database 'pagechecksumtest' from version 539 to the current version 611.
Database 'pagechecksumtest' running the upgrade step from version 539 to version 551.
(...)
Database 'pagechecksumtest' running the upgrade step from version 610 to version 611.
RESTORE DATABASE successfully processed 97 pages in 0.047 seconds (16.754 MB/sec).</em></pre>
<pre><span style="color: #000080;">select name, page_verify_option_desc from sys.databases where name = 'pagechecksumtest'</span></pre>
<pre><em>name                        page_verify_option_desc
-------------------------   -----------------------------------
pagechecksumtest            TORN_PAGE_DETECTION</em></pre>
<p>Donc il faut bien penser à l&#8217;activer à la suite de la migration pour assurer un contrôle optimal:</p>
<pre><span style="color: #000080;">alter database pagechecksumtest set PAGE_VERIFY CHECKSUM</span></pre>
<p>Attention, les pages ne sont pas protégées pour autant immédiatement après: il faudra qu&#8217;elles suivent un cycle complet : qu&#8217;elles soient luent depuis le disque vers le buffer pool, <strong>modifiées</strong>, puis réécrites par le checkpoint pour embarquer la somme de contrôle dans l&#8217;entête.</p>
<p>Si on veut creuser un peu plus, on peut se demander si la page sera bien protégée si elle se trouve dans un filegroup en readonly. En effet, la page ne pouvant pas être modifiée, le checkpoint ne pourra pas marquer le checksum dans son entête (on peut le voir avec un dbcc page, en regardant la valeur de <em>m_flagBits</em> qui normalement doit embarquer 0&#215;200 dans son bitmap pour montrer que le checksum a été calculé).</p>
<p><strong>Scénario: </strong>je pars sur une base fraîchement migrée, je choisis d&#8217;ajouter un filegroup  et de créer des données dedans, pour enfin le passer en read-only. Et ensuite, je me rends compte que PAGE_VERIFY est toujours sur TORN_PAGE_DETECTION, donc je le passe sur CHECKSUM. Est-ce que l&#8217;écrasement de données par un filter driver ou tout autre logiciel tiers s&#8217;exécutant sous NTFS sera vue par SQL Server ?</p>
<p>Voici la repro pour vous permettre de vous faire votre propre idée:</p>
<p>1) Sur une instance en SQL Server 2000, créer une base, une table et sauvegarder la base:</p>
<pre><span style="color: #000080;">create database tpdtest
use tpdtest
create table T1(a numeric identity, b char(1))
insert into T1 values ('A')
backup database tpdtest to disk='F:\SQLDATA$SQL2000\BACKUP\tpdtest.bak' with init, stats</span></pre>
<p>2) Remonter la base sur une instance 2005 ou 2008, ajouter un filegroup, déplacer la table dans ce filegroup et le passer en READONLY:</p>
<pre><span style="color: #000080;">restore database tpdtest from disk='F:\SQLDATA$SQL2000\BACKUP\tpdtest.bak'
with move 'tpdtest' to 'E:\SQLDATA$SQL2005\DATA\tpdtest.mdf',
move 'tpdtest_log' to 'F:\SQLDATA$SQL2005\LOG\tpdtest_log.ldf',
stats, replace

</span><span style="color: #000080;">alter database tpdtest add filegroup RO_tpdtest
alter database tpdtest add file(name='RO_tpdtest',
filename='E:\SQLDATA$SQL2005\DATA\RO_tpdtest.ndf') to filegroup RO_tpdtest
use tpdtest
create unique clustered index UCQ_T1_a on T1(a) on RO_tpdtest
alter database tpdtest modify filegroup RO_tpdtest readonly</span></pre>
<p>Oulala mais j&#8217;ai oublié de passer PAGE_VERIFY sur CHECKSUM, vite:</p>
<pre><span style="color: #000080;">alter database tpdtest set PAGE_VERIFY CHECKSUM</span></pre>
<p>Et là je simule une corruption de données avec un éditeur héxa dans la page de données. Un coup de dbcc ind pour identifier la page en question:</p>
<pre><span style="color: #000080;">dbcc ind('tpdtest','T1',1)</span></pre>
<pre><em>PageFID    PagePID    IAMFID      IAMPID      ObjectID      PageType
---------  ---------  ----------  ----------  ------------  -----------
3          9          NULL        NULL        1977058079    10
3          8          3           9           1977058079    1</em></pre>
<p>La page en question est la page 8 dans le fichier  3, donc en convertissant 8 en offset, on obtient (8*8192) = 0&#215;10000.  A partir de là, je passe la base offline et avec un éditeur hexa de mon choix, je m&#8217;en vais écraser la valeur &#8216;A&#8217; avec une autre valeur, &#8216;C&#8217; par exemple:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/04/corruption.jpg"><img class="alignnone size-full wp-image-916" title="corruption" src="http://blog.capdata.fr/wp-content/uploads/2010/04/corruption.jpg" alt="" width="648" height="144" /></a></p>
<p>A ce niveau-là, il est important de ne pas toucher aux premiers octets de l&#8217;entête, car dans ce cas le mécanisme de TPD jouerait son rôle et on verrait une erreur 824 pointer son nez. On veut vraiment simuler une corruption au beau milieu de la page. On remet la base en ligne et on va lire la valeur:</p>
<pre><span style="color: #000080;">alter database tpdtest set online
use tpdtest
select * from T1</span></pre>
<pre><em>a   b
--  --
1    C</em></pre>
<p>Oooops. ..</p>
<p>A titre de comparaison, en créant le même cas dans un filegroup en read-write:</p>
<pre><span style="color: #000080;">use tpdtest
create table T2(a numeric identity, b char(1))
create unique clustered index UCQ_T2_a on T2(a)
insert into T2 values ('A')
dbcc ind('tpdtest','T2',1)</span></pre>
<pre><em> </em><em>PageFID    PagePID    IAMFID      IAMPID      ObjectID      PageType
---------  ---------  ----------  ----------  ------------  -----------
1          25          NULL        NULL        </em>2089058478    <em> </em><em>10
1          15          1           25          </em>2089058478    <em></em><em>1

</em></pre>
<p>La page est la 15, donc en ouvrant le fichier MDF, à l&#8217;offset (15*8192) = 0&#215;1E000, on refait la même vilaine corruption au même endroit:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/04/corruption2.jpg"><img class="alignnone size-full wp-image-939" title="corruption2" src="http://blog.capdata.fr/wp-content/uploads/2010/04/corruption2.jpg" alt="" width="626" height="82" /></a></p>
<p>Mais cette fois lorsque l&#8217;on veut relire la page:</p>
<pre><span style="color: #000080;">alter database tpdtest set online
use tpdtest
select * from T2</span></pre>
<pre><span style="color: #ff6600;"><em>Msg 824, Level 24, State 2, Line 1</em></span></pre>
<p><span style="color: #ff6600;"><em>SQL Server detected a logical consistency-based I/O error: incorrect checksum (expected: 0xb3834c64; actual: 0xb2834c64). It occurred during a read of page (1:15) in database ID 21 at offset 0&#215;0000000001e000 in file &#8216;E:\SQLDATA$SQL2005\DATA\tpdtest.mdf&#8217;.<br />
Additional messages in the SQL Server error log or system event log may provide more detail. This is a severe error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB).<br />
This error can be caused by many factors; for more information, see SQL Server Books Online.</em></span></p>
<p>Le CHECKSUM est un superset de TPD, donc ça marche.</p>
<p><strong>Donc résumé: </strong><br />
- Quand on migre, il faut penser aussi à modifier PAGE_VERIFY et le passer sur CHECKSUM car ce n&#8217;est pas automatique.<br />
- Le checksum en question ne sera implémenté qu&#8217;une fois la page lue depuis le disque, modifiée, puis réécrite par le CHECKPOINT.<br />
- Les données dans les filegroups en read_only ne sont pas pour autant protégés. Ils conservent le TPD comme seul mode de protection.</p>
<p>A+ David B.</p>
<p><script src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO" type="text/javascript"></script><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/mythe-torn-page-detection-est-moins-couteux-que-checksum/" rel="bookmark" title="1 septembre 2010">Mythe: TORN PAGE DETECTION est moins coûteux que CHECKSUM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/modifier-la-collation-dune-base-sql-2005/" rel="bookmark" title="30 septembre 2009">Modifier la Collation d&#8217;une base SQL 2005</a> (Louis HOCHBERG) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 2.536 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%2Fmodifier-page_verify-apres-une-migration-depuis-sql-2000%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmodifier-page_verify-apres-une-migration-depuis-sql-2000%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/oOqII1XwHTs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/</feedburner:origLink></item>
		<item>
		<title>Un trigger fait-il parti d’une transaction ?</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/bOqkojEfZBQ/</link>
		<comments>http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 13:31:54 +0000</pubDate>
		<dc:creator>Cédric PEINTRE</dc:creator>
				<category><![CDATA[Général]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Sybase]]></category>
		<category><![CDATA[ACID]]></category>
		<category><![CDATA[atomique]]></category>
		<category><![CDATA[transaction]]></category>
		<category><![CDATA[trigger]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=430</guid>
		<description><![CDATA[C&#8217;est une question que l&#8217;on peut se poser, même si la réponse parait évidente, nous ne sommes pas à l&#8217;abri d&#8217;éventuelles surprises. Verdict à la fin de ce post !
C&#8217;est d&#8217;ailleurs une question que l&#8217;on s&#8217;est posée, autour de la machine café, et qui du coup a fait l&#8217;objet d&#8217;un petit exercice avec Oracle, SQL [...]]]></description>
			<content:encoded><![CDATA[<p>C&#8217;est une question que l&#8217;on peut se poser, même si la réponse parait évidente, nous ne sommes pas à l&#8217;abri d&#8217;éventuelles surprises. Verdict à la fin de ce post !</p>
<p>C&#8217;est d&#8217;ailleurs une question que l&#8217;on s&#8217;est posée, autour de la machine café, et qui du coup a fait l&#8217;objet d&#8217;un petit exercice avec Oracle, SQL Server, MySQL et Sybase&#8230; Bon, je vous rassure, nous ne faisons pas que parler bases de données pendant les pauses café mais ça arrive, parfois.</p>
<h2>Place aux tests : Un trigger fait-il parti d&#8217;une transaction ?</h2>
<h3><span style="text-decoration: underline;">Test Oracle :</span></h3>
<pre>SQL &gt; create table t2 ( cnt int );
 SQL &gt; insert into t2 values ( 0 );
 SQL &gt; commit;
 SQL &gt; create table t ( x int check ( x&gt;0 ) );</pre>
<pre>SQL &gt; create trigger t_trigger
 before insert or delete on t for each row
 begin
 if ( inserting ) then
 update t2 set cnt = cnt +1;
 else
 update t2 set cnt = cnt -1;
 end if;
 dbms_output.put_line( 'I fired and updated ' ||sql%rowcount || ' rows'  );
 end;
 /</pre>
<p><span style="text-decoration: underline;">Résultat : OUI<br />
</span></p>
<pre>SQL &gt; set serveroutput on
 SQL &gt; insert into t values (1);
 I fired and updated 1 rows
 1 row created.
 SQL &gt; insert into t values(-1);
 I fired and updated 1 rows
 insert into t values(-1)
 *
 ERROR at line 1:
 ORA-02290: check constraint (SYS_C009597) violated
 SQL &gt; select * from t2;
 CNT
 ----------
 1</pre>
<h3><span style="text-decoration: underline;">Test MS SQL Server :</span></h3>
<pre>use tempdb
 go</pre>
<pre>create table t2 ( cnt int )
 insert into  t2 values ( 0 )
 select * from t2</pre>
<pre>create table t ( x int check  ( x&gt;0 ) )</pre>
<pre>drop trigger t_trigger
 create trigger t_trigger  on t for insert
 as
 begin
 update t2 set cnt = cnt +1
 print( 'I fired and updated ' + CAST(@@ROWCOUNT AS NVARCHAR(8))  + '  rows' )
 end</pre>
<p><span style="text-decoration: underline;">Résultat : OUI<br />
</span></p>
<pre>begin tran
 insert into t values(2);
 insert into t values(-1);</pre>
<pre>(1 row(s) affected)
 I fired and updated  1 rows</pre>
<pre>(1 row(s) affected)
 Msg 547, Level 16, State  0, Line 4
 The INSERT statement conflicted with the CHECK constraint  "CK__t__x__7A5DD7C8". The conflict occurred in database "tempdb", table  "dbo.t", column 'x'.
 The statement has been terminated.</pre>
<h3><span style="text-decoration: underline;">Test MySQL (InnoDB) :</span></h3>
<p>Au passage, cela m&#8217;a permis de découvrir que les contraintes <em>CHECK </em>n&#8217;étaient  pas prises en charge par MySQL : <em>The <code>CHECK</code> clause is  parsed but ignored by all storage engines</em></p>
<pre>mysql&gt; set autocommit=off;
 Query OK, 0 rows affected (0.02  sec)</pre>
<pre>mysql&gt; use test
 Database changed
 mysql&gt; create  table t2 ( cnt int ) engine=innodb;
 Query OK, 0 rows affected (0.11  sec)</pre>
<pre>mysql&gt; insert into t2 values ( 0 );
 Query OK, 1 row  affected (0.02 sec)</pre>
<pre>mysql&gt; commit;
 Query OK, 0 rows  affected (0.11 sec)</pre>
<pre>mysql&gt; create table t ( x int primary key)  engine=innodb;
 Query OK, 0 rows affected (0.09 sec)</pre>
<pre>mysql&gt;  delimiter //</pre>
<pre>mysql&gt; create trigger t_trigger
 -&gt;             before insert on t for each row
 -&gt;              begin
 -&gt;             update t2 set cnt = cnt +1;
 -&gt;             end;
 -&gt; //
 Query OK, 0 rows affected (0.11  sec)</pre>
<pre>mysql&gt; delimiter ;</pre>
<p><span style="text-decoration: underline;">Résultat : OUI<br />
</span></p>
<pre>mysql&gt; insert into t values (1);
 Query OK, 1 row affected  (0.02 sec)</pre>
<pre>mysql&gt; insert into t values (1);
 ERROR 1062  (23000): Duplicate entry '1' for key 'PRIMARY'</pre>
<pre>mysql&gt; select *  from t2;
 +------+
 | cnt  |
 +------+
 |    1 |
 +------+
 1 row in set (0.00 sec)</pre>
<h3><span style="text-decoration: underline;">Test Sybase :<br />
</span></h3>
<pre>1&gt; create trigger T1_ins_tr on T1 for insert</pre>
<pre>2&gt; as</pre>
<pre> 3&gt; begin</pre>
<pre> 4&gt; select 1/0</pre>
<pre> 5&gt; end</pre>
<pre> 6&gt; go</pre>
<p><span style="text-decoration: underline;">Résultat : OUI<br />
</span></p>
<pre>5&gt; begin tran
 6&gt; go
 1&gt; insert into T1 values ('kjhkjhkjh')
 2&gt; go
 Msg 3607, Level 16, State 0:
 Server 'ASE1502', Procedure 'T1_ins_tr', Line 4:
 Divide by zero occurred.</pre>
<pre>-----------
 1&gt; select @@trancount
 2&gt; go</pre>
<pre>-----------
 0</pre>
<pre>(1 row affected)</pre>
<h2>Résultat des tests : LE VERDICT !</h2>
<p>Oui, un trigger fait bien parti d&#8217;une transaction, quel que soit le SGBD, enfin, au moins sur Oracle, SQL Serveur, MySQL et Sybase.</p>
<p>Je vous laisse faire vos tests sur DB2, Postgre et consorts&#8230; N&#8217;hésitez pas à nous faire un retour dans les commentaires.</p>
<p>A+<br />
Cédric<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/saines-lectures/" rel="bookmark" title="25 août 2010">Saines lectures</a> (David BAFFALEUF) [SQL Server]</li>
<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/sql-server-regles-dinstallation-de-base-episode-1/" rel="bookmark" title="18 juin 2009">Règles d&#8217;installation de base (épisode 1)</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.728 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%2Fun-trigger-fait-il-parti-dune-transaction%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fun-trigger-fait-il-parti-dune-transaction%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/bOqkojEfZBQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/</feedburner:origLink></item>
		<item>
		<title>Insert et Update en une seule fois avec MERGE</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/DveHUp_1JGw/</link>
		<comments>http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 12:59:13 +0000</pubDate>
		<dc:creator>Guillaume DEFENDINI</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[insert]]></category>
		<category><![CDATA[merge]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[Sql server 2008]]></category>
		<category><![CDATA[update]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=852</guid>
		<description><![CDATA[Combien de fois le doute s&#8217;installe : Les lignes existent-elles des 2 cotés ? Jusqu&#8217;à la version 2005, la méthode consistait à faire un select , puis si la ligne n&#8217;existait pas dans l&#8217;autre table on l&#8217;insérait, sinon on la mettait à jour.
Depuis la version 2008, Sql server nous propose de faire tout ça en [...]]]></description>
			<content:encoded><![CDATA[<p>Combien de fois le doute s&#8217;installe : Les lignes existent-elles des 2 cotés ? Jusqu&#8217;à la version 2005, la méthode consistait à faire un select , puis si la ligne n&#8217;existait pas dans l&#8217;autre table on l&#8217;insérait, sinon on la mettait à jour.</p>
<p>Depuis la version 2008, Sql server nous propose de faire tout ça en une seule passe grâce à l&#8217;instruction MERGE.</p>
<pre><span style="color: #0000ff;">CREATE TABLE clients
(client_id INT PRIMARY KEY,
client_nom VARCHAR(10),
client_prenom VARCHAR(10),
Date_naissance DATETIME)

CREATE TABLE prospects
( prospect_id INT PRIMARY KEY,
prospect_nom VARCHAR(10),
prospect_prenom VARCHAR(10),
Date_naissance DATETIME)</span>

<span style="color: #0000ff;">INSERT INTO clients VALUES</span>
<span style="color: #3366ff;">(1,'Dupont', 'Guy','1988-01-01'), (3,'Durand', 'Nicole','1990-03-10'),
(5,'Erie', 'Caroline','1984-11-22'), (7,'Toche', 'vincent','1977-07-07'),
(8,'Lagerec', 'Isabelle','1989-05-08')
</span>
<span style="color: #0000ff;">INSERT INTO prospects VALUES </span>
<span style="color: #3366ff;">(1,'Dupont', 'Guy','1977-02-02'),(2,'Kyle', 'Dorine','1981-11-11'),
(4,'Ravole', 'Nicolas','1982-02-06'),(5,'Erie', 'Caroline','1984-12-05'),
(6,'Kent', 'Cyril','1982-07-15')</span>
<span style="color: #0000ff;">
MERGE clients USING prospects ON (clients.client_id=prospects.prospect_id)
WHEN NOT MATCHED THEN
 INSERT  values (prospects.prospect_id,prospects.prospect_nom,
 prospects.prospect_prenom,prospects.Date_naissance)
WHEN MATCHED THEN
 UPDATE  SET  clients.Date_naissance=prospects.Date_naissance;</span></pre>
<div>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/03/merge1.jpg"><img class="alignnone size-full wp-image-865" title="merge" src="http://blog.capdata.fr/wp-content/uploads/2010/03/merge1.jpg" alt="" width="640" height="400" /></a><br />
On retrouve bien les lignes de la table prospects et les lignes de la table clients qui ont été modifiés.<br />
Au niveau syntaxique, il faut simplement penser au ;</p>
</div>
<p><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<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/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 3.656 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%2Finsert-et-update-en-une-seule-fois-cest-possible-merge%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Finsert-et-update-en-une-seule-fois-cest-possible-merge%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/DveHUp_1JGw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/</feedburner:origLink></item>
		<item>
		<title>Que faire des “[Warning] Aborted connection” avec MySQL ?</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/robOtajunT0/</link>
		<comments>http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 16:44:58 +0000</pubDate>
		<dc:creator>Cédric PEINTRE</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Aborted connection]]></category>
		<category><![CDATA[Got an error reading communication packets]]></category>
		<category><![CDATA[log-warnings]]></category>
		<category><![CDATA[[Warning] Aborted connection]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=495</guid>
		<description><![CDATA[Un petit post sur cet avertissement que l&#8217;on rencontre bien souvent chez nos clients MySQL.
Ceux qui utilisent MySQL ont sans doute déjà croisé ce type de warning et découverts que les informations fournies par MySQL sur le sujet sont limitées (ainsi que les infos que l&#8217;on peut glaner sur le net)
Je veux parler ici d&#8217;erreurs [...]]]></description>
			<content:encoded><![CDATA[<p>Un petit post sur cet avertissement que l&#8217;on rencontre bien souvent chez nos clients MySQL.<br />
Ceux qui utilisent MySQL ont sans doute déjà croisé ce type de <em>warning </em>et découverts que les informations fournies par MySQL sur le sujet sont limitées (ainsi que les infos que l&#8217;on peut glaner sur le net)</p>
<p>Je veux parler ici d&#8217;erreurs récurrentes, qui se produisent de façon aléatoire plusieurs fois par jour, pas d&#8217;une erreur liée à un mauvais mot de passe ou à des privilèges insuffisants qui peuvent également générer ce type d&#8217;erreur.</p>
<h3>Ce qu&#8217;en dit MySQL :</h3>
<p>La page de documentation concernant ce problème est la suivante :</p>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/communication-errors.html" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/communication-errors.html</a></li>
</ul>
<p>En fait, il y a deux raisons essentielles pour lesquelles MySQL est susceptible de renvoyer cette erreur : Des problèmes liés au réseau ou des problèmes liés au mode de sortie de session dans le code applicatif.<br />
Pour ce dernier cas, attention à bien utiliser la fonction <a title="21.9.3.5. mysql_close()" href="http://dev.mysql.com/doc/refman/5.1/en/mysql-close.html" target="_blank"><code>mysql_close()</code></a> dans votre code applicatif.</p>
<h3>Dans la pratique, que faire de cet avertissement ?</h3>
<p>La première question à se poser est de savoir si ce problème affecte, d&#8217;une façon ou d&#8217;une autre, votre production.<br />
Pour le savoir, plusieurs sources sont à votre disposition : Les utilisateurs qui peuvent vous remonter des erreurs, les logs applicatifs ou vos outils de monitoring qui clignotent trop régulièrement&#8230;</p>
<p>Si l&#8217;impact de cette erreur sur votre production est nulle, je vous recommande simplement de désactiver la remontée d&#8217;info la concernant via le paramètre <a href="http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_log-warnings" target="_blank">log-warnings</a> :</p>
<ul>
<li>set global log-warnings = 1;</li>
</ul>
<p>Attention toutefois, la manipulation de ce paramètre peut entraîner la désactivation complète de tous les <em>warnings</em>. Rapprochez vous de la documentation de ce paramètre pour plus d&#8217;infos :</p>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_log-warnings" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_log-warnings</a></li>
</ul>
<p><span style="text-decoration: underline;">Sinon, je vous invite à suivre le mode opératoire suivant :</span></p>
<ul>
<li>Demander aux admins réseau de vérifier les différents composants réseau de votre architecture afin d&#8217;identifier d&#8217;éventuels problèmes</li>
<li>Vérifier votre code applicatif et la bonne utilisation de la fonction <a title="21.9.3.5. mysql_close()" href="http://dev.mysql.com/doc/refman/5.1/en/mysql-close.html" target="_blank"><code>mysql_close()</code></a></li>
<li>Vérifier que vos clients MySQL ne dépassent pas le <em>timeout </em>de connexion défini par la variable <a href="http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_connect_timeout" target="_blank"><code>connect_timeout</code></a></li>
<li>Augmenter la valeur du paramètre <a href="http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_max_allowed_packet" target="_blank"><code>max_allowed_packet</code></a> (cette dernière méthode semble d&#8217;ailleurs porter ses fruits chez un grand nombre d&#8217;utilisateurs)</li>
</ul>
<p>Si ces différentes opérations ne permettent pas d&#8217;identifier ou de régler votre problème, essayez d&#8217;appliquer chaque point préconisé dans la documentation mentionnée en début d&#8217;article et croisez les doigts !</p>
<p>N&#8217;hésitez pas à me faire un retour d&#8217;expérience sur ce point à travers les commentaires. Merci.</p>
<p>Bonne fin de semaine<br />
Cédric.<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<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>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
<li><a href="http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.641 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%2Fque-faire-des-warning-aborted-connection-avec-mysql%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fque-faire-des-warning-aborted-connection-avec-mysql%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/robOtajunT0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/</feedburner:origLink></item>
		<item>
		<title>Intérêt de créer des indexes cluster uniques</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/VgCOiOgTwOo/</link>
		<comments>http://blog.capdata.fr/index.php/interet-de-creer-des-indexes-cluster-uniques/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 17:16:24 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[bookmark lookup]]></category>
		<category><![CDATA[dbcc ind]]></category>
		<category><![CDATA[index clusterisé]]></category>
		<category><![CDATA[index non clusterisé]]></category>
		<category><![CDATA[unique]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=768</guid>
		<description><![CDATA[Hello,
Un petit post rapide sur l&#8217;impact que peuvent avoir des valeurs de clés d&#8217;index clusterisé dupliquées sur les pages d&#8217;indexes non clusterisés.
En effet, par défaut la commande CREATE CLUSTERED INDEX va créer un index clusterisé non-unique, qui donc autorise l&#8217;insertion de valeurs dupliquées. Or cela pose un certain nombre de problèmes, notamment lorsque l&#8217;optimiseur choisit [...]]]></description>
			<content:encoded><![CDATA[<p>Hello,</p>
<p>Un petit post rapide sur l&#8217;impact que peuvent avoir des valeurs de clés d&#8217;index clusterisé dupliquées sur les pages d&#8217;indexes non clusterisés.</p>
<p>En effet, par défaut la commande CREATE CLUSTERED INDEX va créer un index clusterisé non-unique, qui donc autorise l&#8217;insertion de valeurs dupliquées. Or cela pose un certain nombre de problèmes, notamment lorsque l&#8217;optimiseur choisit d&#8217;utiliser un index non clusterisé pour résoudre un prédicat et de faire des lectures additionnelles dans l&#8217;index clusterisé pour lire des colonnes non inclues dans l&#8217;index NC, ce qu&#8217;on appelle un <em>bookmark lookup</em> (bookmark = marque pages).</p>
<p><em><strong>Exemple: une table MATABLE (col1,col2,col3) avec un index clusterisé sur col1 (bigint) et un index non clusterisé sur col2 (datetime)<br />
</strong></em></p>
<pre>set showplan_text on
select col1, col2, col3 from MATABLE where col2 = '2010/03/16'</pre>
<pre> |--Nested Loops(Inner Join, OUTER REFERENCES:([CAPDATA].[dbo].[MATABLE].[col1]))
    |--Index Seek(OBJECT:([CAPDATA].[dbo].[MATABLE].[MATABLE_IDXNCLU_col2]),
                 SEEK:([CAPDATA].[dbo].[MATABLE].[col2]='2010-03-16 00:00:
                  00.000') ORDERED FORWARD)
    |--Clustered Index Seek(OBJECT:([CAPDATA].[dbo].[MATABLE].[MATABLE_IDXCLU_col1]),
                 SEEK:([CAPDATA].[dbo].[MATABLE].[col1]=[CAPDATA].[dbo].[MATABLE].[col1])
                 LOOKUP ORDERED FORWARD)</pre>
<p>L&#8217;opérateur<strong> Index Seek</strong> est celui utilisé pour résoudre le prédicat sur la date et le <strong>Clustered Index Seek</strong> est l&#8217;opérateur choisi par l&#8217;optimiseur pour lire les colonnes additionnelles col1 et col3 (LOOKUP ORDERED FORWARD&#8230;).</p>
<p>Dans les pages  d&#8217;un index non clusterisé, on va stocker  à la fois la valeur de la clé de l&#8217;index NC (donc ici col2) ainsi que la valeur de la clé de l&#8217;index clusterisé (donc ici col1), qui va servir de pointeur entrant dans l&#8217;index clusterisé pour faire ce fameux <em>Bookmark Lookup</em>. La valeur de col1 représente donc le &#8216;marque-pages&#8217; vers les pages de l&#8217;index clusterisé.</p>
<p>Maintenant comment savoir vers quelle page l&#8217;index NC va pointer lorsque col1 peut se trouver à plusieurs endroits de l&#8217;index clusterisé (lorsqu&#8217;il y a des valeurs dupliquées) ? Lorsqu&#8217;il y a des valeurs de clé dupliquées dans l&#8217;index clusterisé, SQL Server est obligé d&#8217;ajouter en plus de col2 et col1 un identifiant unique de type uniquifier (non visible par les outils courants SSMS et autres sp_helpindex) pour pointer vers la bonne ligne dans la bonne page. Et cet uniquifier ajoute 16 octets supplémentaires par ligne dans les pages de l&#8217;index NC.</p>
<p>Pour le démontrer, nous allons d&#8217;abord créer une table TABLE1 avec 3 colonnes, un index clusterisé non unique sur col1 et un index non clusterisé non unique sur col2.</p>
<pre>CREATE TABLE TABLE1 (
 col1 bigint NOT NULL,
 col2 bigint NOT NULL DEFAULT 10000,
 col3 CHAR (400) NOT NULL DEFAULT 'abcdefghijklmnopqrstuvwxyz');

CREATE CLUSTERED INDEX TABLE1_IDXCLU_col1 ON TABLE1 (col1);
CREATE NONCLUSTERED INDEX TABLE1_IDXNCLU_col2 ON TABLE1 (col2);
GO</pre>
<p>Nous allons ensuite alimenter la table  en forçant la génération de valeurs dupliquées:</p>
<pre>DECLARE @a INT, @random BIGINT;
SELECT @a = 1;
SELECT @random = cast(rand(@a)*100 as bigint);
WHILE (@a &lt; 10000)
BEGIN
 INSERT INTO TABLE1 VALUES (@random, DEFAULT, DEFAULT);
 SELECT @a = @a + 1;
 SELECT @random = cast(rand(@a)*100 as bigint);
END;
GO</pre>
<p>En insérant 9999 valeurs comprises entre 1 et 100, il y a des chances pour que j&#8217;obtienne un certain nombre de valeurs en double:</p>
<pre>select col1, COUNT(*) as compte
from TABLE1 group by col1 having COUNT(*) &gt; 1</pre>
<pre>col1   compte
----    ---------
89    531
72    537
75    537
78    536
86    537
81    536
84    536
87    536
73    537
85    537
76    537
88    537
79    537
82    537
77    537
80    537
71    344
83    537
74    536</pre>
<p>Maintenant je vais m&#8217;intéresser à la structure de mon index NC, en utilisant l&#8217;option DETAILED de la DMF sys.dm_db_index_physical_stats(), afin de voir l&#8217;espace utilisé à chaque niveau de l&#8217;index NC ( la valeur 2 = indid du NC):</p>
<pre>select index_level, min_record_size_in_bytes,
max_record_size_in_bytes, avg_record_size_in_bytes,
record_count, page_count
from sys.dm_db_index_physical_stats (db_id('CAPDATA'),object_id('TABLE1'),2,NULL,'DETAILED')

index_level min_record_size_in_bytes max_record_size_in_bytes avg_record_size_in_bytes
----------- ------------------------ ------------------------ ------------------------
0           17                        25                       24,984    
1           23                        31                       30,764</pre>
<pre>record_count         page_count
-------------------- --------------------
9999                 34
34                   1</pre>
<p>L&#8217;index NC compte 35 pages, 1 pages de niveau root et 34 pages de niveau feuille. Le niveau 1 représente le niveau root. Il compte une seule page donc et 34 lignes pointant vers les 34 pages du niveau inférieur. On voit que les tailles minimale et maximale varient entre 23 et 31 octets. Celà est dû au fait que presque chaque ligne  contient en plus des valeurs de col2 et col1 un uniquifier permettant de distinguer les lignes dupliquées qui sont référencées. On peut le voir en allant lire le contenu de cette root page. Le dbcc ind() va nous permettre d&#8217;identifier cette root page:</p>
<pre>dbcc ind('CAPDATA','TABLE1',2)
PageFID  PagePID     IAMFID    IAMPID      ObjectID    IndexID     (...)            IndexLevel      (...)
-------  ----------- ------    ----------- ----------- ----------- --------------- --------------------       
1        25916       NULL      NULL        1138103095    2                             0   
1        25915       1         25916       1138103095    2                             0
1        23719       1         25916       1138103095    2                             1
(...)</pre>
<p>index_level à 1, notre page est la <strong>23719</strong>. un bref dbcc page:</p>
<pre>dbcc traceon(3604)
dbcc page(5,1,23719,3)
FileId PageId      Row    Level  ChildFileId ChildPageId col2 (key)           col1 (key)           UNIQUIFIER (key) KeyHashValue
------ ----------- ------ ------ ----------- ----------- -------------------- -------------------- ---------------- ----------------
1    23719         0       1      1           25915       NULL                  NULL               NULL              NULL
1    23719         1       1      1           23728       10000                 71                 300               NULL
1    23719         2       1      1           23729       10000                 72                 256               NULL
1    23719         3       1      1           23730       10000                 73                 19                NULL
(...)</pre>
<p>On voit qu&#8217;une colonne a donc été ajoutée. On pourra faire les mêmes observations avec les pages de niveau feuille de l&#8217;index NC.</p>
<p>Maintenant si on crée une seconde table TABLE 2 avec cette fois un index clusterisé UNIQUE:</p>
<pre>CREATE TABLE TABLE2 (
 col1 bigint NOT NULL,
 col2 bigint NOT NULL DEFAULT 10000 ,
 col3 CHAR (400) NOT NULL DEFAULT 'abcdefghijklmnopqrstuvwxyz');

CREATE UNIQUE CLUSTERED INDEX TABLE2_IDXCLU_col1 ON TABLE2 (col1);
CREATE NONCLUSTERED INDEX TABLE2_IDXNCLU_col2 ON TABLE2 (col2);
GO

DECLARE @a INT;
SELECT @a = 1;
WHILE (@a &lt; 10000)
BEGIN
 INSERT INTO TABLE2 VALUES (@a, DEFAULT, DEFAULT);
 SELECT @a = @a + 1;
END;
GO</pre>
<p>Jetons un coup d&#8217;oeil à sa structure:</p>
<pre>select index_level,min_record_size_in_bytes, max_record_size_in_bytes, avg_record_size_in_bytes, record_count, page_count
from sys.dm_db_index_physical_stats (db_id('CAPDATA'),object_id('TABLE2'),2,NULL,'DETAILED')</pre>
<pre>index_level min_record_size_in_bytes max_record_size_in_bytes avg_record_size_in_bytes record_count         page_count
----------- ------------------------ ------------------------ ------------------------ -------------------- --------------------
0            17                      17                        17                       9999                 24
1            23                      23                        23                        24                  1</pre>
<p>Il ne fait plus que 25 pages (24+1), tout simplement parce qu&#8217;il n&#8217;y a plus de uniquifier dans les pages. La taille moyenne de chaque ligne est redevenue normale. On retrouve la root page correspondante de la même façon que plus haut, et en lisant son contenu:</p>
<pre>dbcc traceon(3604)
dbcc page(5,1,23745,3)
FileId PageId      Row    Level  ChildFileId ChildPageId col2 (key)           col1 (key)           KeyHashValue
------ ----------- ------ ------ ----------- ----------- -------------------- -------------------- ----------------
1      23745       0       1        1         25923         NULL                NULL                NULL
1      23745       1       1        1         23746         10000               427                 NULL
1      23745       2       1        1         23747         10000               853                 NULL
(...)</pre>
<p>La colonne UNIQUIFIER a disparu. Donc morale de l&#8217;histoire, il faut penser à ajouter le mot-clé UNIQUE dans les créations d&#8217;indexes clusterisés.</p>
<p>J&#8217;ajoute aussi que le uniquifier n&#8217;est ajouté que lorsqu&#8217;il y a effectivement des doublons dans l&#8217;index clusterisé. Tant qu&#8217;il n&#8217;y a pas de doublon détecté, même si l&#8217;index a été créé sans préciser UNIQUE, il n&#8217;y aura pas de colonne additionnelle.</p>
<p>A+, 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/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/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
<li><a href="http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 4.074 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%2Finteret-de-creer-des-indexes-cluster-uniques%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Finteret-de-creer-des-indexes-cluster-uniques%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/VgCOiOgTwOo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/interet-de-creer-des-indexes-cluster-uniques/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/interet-de-creer-des-indexes-cluster-uniques/</feedburner:origLink></item>
		<item>
		<title>Scruter les journaux d’évènements Windows avec LogParser</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/_mPaU4xJhF0/</link>
		<comments>http://blog.capdata.fr/index.php/scruter-les-journaux-devenements-windows-avec-logparser/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 18:01:52 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[eventlog]]></category>
		<category><![CDATA[journaux d'évènements]]></category>
		<category><![CDATA[logparser]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=632</guid>
		<description><![CDATA[Un petit post sur un outil bien pratique pour tous ceux qui rament pour écrire des scripts sous Windows. Un des outils indispensables dont toute production doive se doter est un analyseur de journaux d&#8217;erreur.
Logparser est un petit exécutable fourni gratuitement par Microsoft et qui permet de lire des fichiers structurés propriétaires tels que les [...]]]></description>
			<content:encoded><![CDATA[<p>Un petit post sur un outil bien pratique pour tous ceux qui rament pour écrire des scripts sous Windows. Un des outils indispensables dont toute production doive se doter est un analyseur de journaux d&#8217;erreur.</p>
<p><strong>Logparser </strong>est un petit exécutable fourni gratuitement par Microsoft et qui permet de lire des fichiers structurés propriétaires tels que les eventlogs *.EVT, mais aussi les fichiers CVS, ETW, REG, etc&#8230; Tout d&#8217;abord il s&#8217;agit de le <a title="Logparser 2.2" href="http://www.google.com/url?sa=t&amp;source=web&amp;ct=res&amp;cd=1&amp;ved=0CAkQFjAA&amp;url=http%3A%2F%2Fwww.microsoft.com%2Fdownloads%2Fdetails.aspx%3FFamilyID%3D890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;rct=j&amp;q=download+logparser&amp;ei=m0-aS6yaLcT04gbn-fl7&amp;usg=AFQjCNGYcYCEUI2OdAX2GV_EO6ETNHqXnA&amp;sig2=vVABqIEJDhihHTm_mfP7CQ">télécharger</a> et de l&#8217;installer en trois ou quatre clics. Je passe rapidement sur l&#8217;install, il faudra juste bien penser à ajouter le chemin de logparser.exe dans votre PATH.</p>
<p>L&#8217;avantage principal est qu&#8217;il utilise un pseudo langage proche du SQL pour effectuer des recherches. Par exemple, si je veux remonter les 3 dernières erreurs dans le journal Application :</p>
<pre>$ logparser "SELECT TOP 3 TimeGenerated, SourceName, Message
from Application
where eventtype=1
order by TimeGenerated desc" -i:EVT -stats:OFF</pre>
<pre>TimeGenerated           SourceName      Message
-------------------     -----------     ------------------------------------------------
2010-03-11 13:03:39     MSSQLSERVER     Database mirroring connection error 2 'Connection ...
2010-03-11 13:03:17     MSSQLSERVER     Database mirroring connection error 4 '64...
2010-03-11 13:02:57     MSSQLSERVER     The mirroring connection to "tcp://192...</pre>
<p>On peut utiliser le mot-clé &#8216;<em>into</em>&#8216; après le SELECT pour indiquer que l&#8217;on souhaite placer le résultat dans un fichier. La répartition des codes erreurs dans les journaux d&#8217;évènements se fait comme suit:</p>
<pre>$ logparser "select distinct EventTypeName, EventType
from Application" -i:EVT -stats:OFF

EventTypeName       EventType
------------------- ---------
Information event   4
Success event       0
Warning event       2
Error event         1
Failure Audit event 16</pre>
<p>On recherchera donc en priorité les eventtype = 1.</p>
<p>Parmi les options intéressantes:</p>
<p><strong>-i</strong>: Donne le type d&#8217;entrée du fichier. exemple, -i:EVT indique que l&#8217;on souhaite lire un fichier *.evt. S&#8217;il n&#8217;est pas indiqué, logparser le trouve tout seul en fonction de l&#8217;entrée.<br />
<strong>-o</strong>: Donne le format de sortie. Par exemple -o:XML pour écrire au format XML. S&#8217;il n&#8217;est pas indiqué, logparser le trouve tout seul en fonction du fichier indiqué dans la clause &#8216;<em>into</em>&#8216;.<br />
<strong>-stats</strong>: ON/OFF: si les stats sont indiquées, alors logparser renvoie le nombre de lignes traitées et le temps passé.<br />
<strong>-q</strong>: ON/OFF: mode quiet, par exemple pour éliminer les entêtes.</p>
<p>Il possède également des fonction d&#8217;agrégation de type <em>GROUP BY / HAVING&#8230; </em>Par exemple pour ramener le nombre d&#8217;erreurs par Source:</p>
<pre>$ logparser "SELECT SourceName, count(*)
from Application where EventType = 1
group by SourceName order by count(*) desc"
-i:EVT -stats:OFF

SourceName                        COUNT(ALL *)
--------------------------------- ------------
MSSQLSERVER                       83
Winlogon                          30
Software Licensing Service        2
Perflib                           2
.NET Runtime Optimization Service 2
SideBySide                        2
SQLDIAG                           1</pre>
<p>Dès lors il devient facile de créer un script qui va régulièrement exécuter une recherche des erreurs remontées dans les journaux <em>Application </em>et <em>System</em>. Nous pouvons utiliser un simple fichier par exemple pour stocker la dernière ligne lue à chaque passage, et nous permettre de repartir de cette ligne à l&#8217;exécution suivante:</p>
<pre>$ logparser "SELECT MAX(RecordNumber) into E:\maxrecod.app.log FROM Application"
-i:EVT -stats:OFF -q:ON
$ cat E:/maxrecod.app.log
3597</pre>
<p>&#8230; et dans un script, affecter le contenu du fichier dans une variable, et utiliser la variable dans une nouvelle recherche. Par exemple sous cygwin:</p>
<pre>MAXRECORD=$(cat E:/maxrecod.app.log)
if [ ! -z ${MAXRECORD} ]
then
      SELECT TimeGenerated, SourceName, Message into E:/Application.err
      from Application where EventType=1 and RecordNumber &gt;= ${MAXRECORD}" 
      -i:EVT -stats:OFF -q:ON
else
      echo "borne invalide"
fi</pre>
<p>A+. 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/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>
<li><a href="http://blog.capdata.fr/index.php/reunion-guss-le-1er-juillet/" rel="bookmark" title="23 juin 2010">Réunion GUSS le 1er juillet !</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
</ul>
<p><!-- Similar Posts took 4.014 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%2Fscruter-les-journaux-devenements-windows-avec-logparser%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fscruter-les-journaux-devenements-windows-avec-logparser%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/_mPaU4xJhF0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/scruter-les-journaux-devenements-windows-avec-logparser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/scruter-les-journaux-devenements-windows-avec-logparser/</feedburner:origLink></item>
		<item>
		<title>XtraDB sauvegarde votre cache, et ça marche !</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/ZYP8Fk6WYfU/</link>
		<comments>http://blog.capdata.fr/index.php/xtradb-sauvegarde-votre-cache-et-ca-marche/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 08:00:30 +0000</pubDate>
		<dc:creator>Cédric PEINTRE</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[innodb buffer pool]]></category>
		<category><![CDATA[innodb_buffer_pool_size]]></category>
		<category><![CDATA[percona]]></category>
		<category><![CDATA[profiling]]></category>
		<category><![CDATA[xtradb]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=643</guid>
		<description><![CDATA[La dernière version de XtraDB, le moteur de stockage proposé par Percona, dispose d&#8217;une fonctionnalité plutôt pertinente avec MySQL : La sauvegarde du cache InnoDB (InnoDB Buffer Pool)
Sauvegarder le cache, oui, mais pour quoi faire ?
Vous devez effectivement comprendre l&#8217;intérêt de la chose si vous vous êtes déjà frotté à l&#8217;administration d&#8217;un MySQL mais je [...]]]></description>
			<content:encoded><![CDATA[<p>La dernière version de XtraDB, le moteur de stockage proposé par Percona, dispose d&#8217;une fonctionnalité plutôt pertinente avec MySQL : La sauvegarde du cache InnoDB (InnoDB Buffer Pool)</p>
<h3>Sauvegarder le cache, oui, mais pour quoi faire ?</h3>
<p>Vous devez effectivement comprendre l&#8217;intérêt de la chose si vous vous êtes déjà frotté à l&#8217;administration d&#8217;un MySQL mais je dois vous avouer qu&#8217;en abordant le sujet pendant la pose café, tout le monde n&#8217;était pas forcement convaincu.</p>
<p>En effet, la mise en œuvre d&#8217;une telle fonctionnalité soulève une autre question : Pourquoi redémarrer MySQL ?</p>
<p>Effectivement, le véritable intérêt de cette sauvegarde est de pouvoir couper son MySQL sans perdre les informations stockées dans le cache. Intérêt évidemment compris de tous dans le cas d&#8217;un crash du serveur MySQL.</p>
<p>Dans les faits, XtraDB permet de sauvegarder et restaurer le cache même si il n&#8217;y a pas eu d&#8217;arrêt de l&#8217;instance. Ce qui peut d&#8217;ailleurs s&#8217;avérer utile dans certaines conditions, après le passage d&#8217;un gros batch par exemple, afin de retrouver un cache d&#8217;activité transactionnelle standard.</p>
<p>Pour en revenir à la question posée par mon collègue, en dehors du contexte de crash, pourquoi redémarrer MySQL ?<br />
Alors que d&#8217;autres éditeurs de bases de données concentrent leurs efforts pour justement limiter au maximum le redémarrage des instances, il semble que MySQL soit plus exposé que les autres à ce type de problématique.<br />
Et effectivement, même si la modification dynamique de paramètres gagne du terrain avec les nouvelles versions, la gestion des fichiers physiques reste problématique dans un environnement de production critique.</p>
<p>Il s&#8217;agit donc ici de se poser la question à l&#8217;envers et c&#8217;est donc pour ces différentes raisons que la sauvegarde du cache de données est pertinente avec MySQL !</p>
<h3>Comment ça marche ?</h3>
<p>Le pré-requis est évidemment d&#8217;installer et d&#8217;utiliser le moteur de stockage XtraDB fourni par Percona (lien en fin d&#8217;article).</p>
<p>Pour comprendre le fonctionnement de cette sauvegarde, j&#8217;ai réalisé un petit test en utilisant le compteur <em>Innodb_buffer_pool_pages_data</em> qui indique combien de pages du cache sont utilisées :</p>
<p>1 &#8211; Arrêt et relance de l&#8217;instance MySQL (Tous les caches sont vidés)</p>
<p>2 &#8211; Je contrôle l&#8217;état de mon cache :</p>
<ul>
<li>mysql&gt; show global status like &#8216;Innodb_buffer_pool_pages_data&#8217;;</li>
</ul>
<pre>+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_buffer_pool_pages_data | 14    |
+-------------------------------+-------+
</pre>
<p>3 &#8211; Je fais une requête simple sur ma table ETAT :</p>
<ul>
<li>mysql&gt; select * from capdata_innodb.ETAT;</li>
</ul>
<p>4 -Nouvelle vérification du cache, à ce stade, la table ETAT a bien été montée dans le cache (au moins une  partie de ses données) :</p>
<ul>
<li>mysql&gt; show global status like &#8216;Innodb_buffer_pool_pages_data&#8217;;</li>
</ul>
<pre>+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_buffer_pool_pages_data | 17    |
+-------------------------------+-------+
</pre>
<p>5 &#8211; Je lance une sauvegarde du cache :</p>
<ul>
<li>mysql&gt; select * from information_schema.XTRADB_ADMIN_COMMAND /*!XTRA_LRU_DUMP*/;</li>
</ul>
<pre>+------------------------------+
| result_message               |
+------------------------------+
| XTRA_LRU_DUMP was succeeded. |
+------------------------------+
</pre>
<p>6 &#8211; Arrêt et relance de l&#8217;instance MySQL (Tous les caches sont vidés)</p>
<p>7 &#8211; Vérification du cache :</p>
<ul>
<li>mysql&gt; show global status like &#8216;Innodb_buffer_pool_pages_data&#8217;;</li>
</ul>
<pre>+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_buffer_pool_pages_data | 14    |
+-------------------------------+-------+</pre>
<p>8 -Restauration du cache :</p>
<ul>
<li>mysql&gt; select * from information_schema.XTRADB_ADMIN_COMMAND /*!XTRA_LRU_RESTORE*/;</li>
</ul>
<pre>+---------------------------------+
| result_message                  |
+---------------------------------+
| XTRA_LRU_RESTORE was succeeded. |
+---------------------------------+
</pre>
<p>9 &#8211; Dernière vérification du cache :</p>
<ul>
<li>mysql&gt; show global status like &#8216;Innodb_buffer_pool_pages_data&#8217;;</li>
</ul>
<pre>+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_buffer_pool_pages_data | 17    |
+-------------------------------+-------+
</pre>
<p>Le cache a bien été restauré, à vous le warm restart facile !</p>
<p>Percona a réalisé un petit benchmark comparatif dont voici le résultat :</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/03/test_xtraDB_CB.png"><img class="aligncenter size-full wp-image-706" title="test_xtraDB_CB" src="http://blog.capdata.fr/wp-content/uploads/2010/03/test_xtraDB_CB.png" alt="" width="796" height="282" /></a></p>
<p>Retrouvez toutes les informations sur le moteur XtraDB ici : <a href="http://www.percona.com/docs/wiki/percona-xtradb:start" target="_blank">http://www.percona.com/docs/wiki/percona-xtradb:start</a><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/sql-server-principes-dune-sauvegarde-a-chaud/" rel="bookmark" title="12 décembre 2008">Principes d&#8217;une sauvegarde à chaud</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/" rel="bookmark" title="6 janvier 2010">MySQL et les tables temporaires internes</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/replication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters/" rel="bookmark" title="18 juin 2009">Attention : publication transactionnelle et indexes non clusters</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
<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>
</ul>
<p><!-- Similar Posts took 3.738 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%2Fxtradb-sauvegarde-votre-cache-et-ca-marche%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fxtradb-sauvegarde-votre-cache-et-ca-marche%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/ZYP8Fk6WYfU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/xtradb-sauvegarde-votre-cache-et-ca-marche/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/xtradb-sauvegarde-votre-cache-et-ca-marche/</feedburner:origLink></item>
		<item>
		<title>Création d’un Dataguard physique</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/IgU8YhKCJG8/</link>
		<comments>http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 14:42:12 +0000</pubDate>
		<dc:creator>Guillaume DEFENDINI</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[archive]]></category>
		<category><![CDATA[Data Guard]]></category>
		<category><![CDATA[standby]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=720</guid>
		<description><![CDATA[Configuration :
Red Hat Enterprise Linux Server release 5.4 (Tikanga)
Oracle 10GR2
PTEST : base primaire
STEST : base standby
Remarque :Toutes les opérations SQL se font connecté en tant que &#8220;as sysdba&#8221; 
1. Configuration  des bases en archivelog et force logging

SQL&#62; ALTER DATABASE FORCE LOGGING;
SQL&#62; alter database archivelog ;
2. Créer une sauvegarde de la base primaire
A) Créer les standby [...]]]></description>
			<content:encoded><![CDATA[<p><em><strong>Configuration </strong></em>:<br />
Red Hat Enterprise Linux Server release 5.4 (Tikanga)<br />
Oracle 10GR2<br />
PTEST : base primaire<br />
STEST : base standby</p>
<p>Remarque :Toutes les opérations SQL se font connecté en tant que &#8220;as sysdba&#8221;<strong> </strong></p>
<p><strong>1. Configuration  des bases en archivelog et force logging<br />
</strong></p>
<p>SQL&gt; ALTER DATABASE FORCE LOGGING;<br />
SQL&gt; alter database archivelog ;</p>
<p><strong>2. Créer une sauvegarde de la base primaire</strong></p>
<p>A) Créer les standby controlfile<br />
SQL&gt; alter database create standby controlfile as ‘/u01/app/oracle/TEST/standby1.ctl’;</p>
<p>B) Créer les standby redo log .<br />
SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE &#8216;/u01/app/oracle/TEST/srl01.log&#8217; SIZE 10M   REUSE;<br />
SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE &#8216;/u01/app/oracle/TEST/srl02.log&#8217; SIZE 10M   REUSE;<br />
SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE &#8216;/u01/app/oracle/TEST/srl03.log&#8217; SIZE 10M   REUSE;<br />
SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE &#8216;/u01/app/oracle/TEST/srl04.log&#8217; SIZE 10M   REUSE;</p>
<p>Il est conseillé :</p>
<ul>
<li> de créer un fichier &#8220;standby redo log&#8221; de plus que les redo log</li>
<li> d&#8217;avoir une taille des standby redo log &gt;= taille des redo log</li>
</ul>
<p>C) Effectuer une sauvegarde de la base primaire ((il est possible de le faire à chaud par rman)</p>
<p>Arrêter la base primaire</p>
<p>Faire une copie physique dans un répertoire de sauvegarde des types de fichier suivants :<br />
- datafiles<br />
- online redo logs<br />
- standby controlfile<br />
- standby redolog</p>
<p>Redémarrer la base primaire</p>
<p><strong>3.  Modification ou création des  paramètres d’initialisation des bases primaire et standby</strong></p>
<p><em>Base ayant le rôle primaire (PTEST) </em>:<br />
log_archive_format=%t_%s_%r.arc<br />
log_archive_dest_2=&#8217;service=STEST LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=STEST&#8217;<br />
log_archive_config=&#8217;DG_CONFIG=(PTEST,STEST)&#8217;<br />
LOG_ARCHIVE_DEST_STATE_2=ENABLE<br />
db_name=TEST<br />
db_unique_name=PTEST<br />
fal_server=STEST<br />
fal_client=PTEST<br />
DB_FILE_NAME_CONVERT=(&#8216;/u01/app/oracle/TESTSTANDBY&#8217;,'/u01/app/oracle/TEST&#8217;)<br />
LOG_FILE_NAME_CONVERT=(&#8216;/u01/app/oracle/TESTSTANDBY&#8217;,'/u01/app/oracle/TEST&#8217;)<br />
standby_archive_dest=/u01/app/oracle/flash_recovery_area/STEST/standby_archive<br />
STANDBY_FILE_MANAGEMENT=AUTO</p>
<p><em> Base ayant le rôle standby (STEST)  :</em><br />
fal_server=PTEST<br />
fal_client=STEST<br />
DB_FILE_NAME_CONVERT=(&#8216;/u01/app/oracle/TEST&#8217;,'/u01/app/oracle/TESTSTANDBY&#8217;)<br />
LOG_FILE_NAME_CONVERT=(&#8216;/u01/app/oracle/TEST&#8217;,'/u01/app/oracle/TESTSTANDBY&#8217;)<br />
STANDBY_ARCHIVE_DEST=/u01/app/oracle/flash_recovery_area/STEST/standby_archive<br />
log_archive_format=%t_%s_%r.dbf<br />
STANDBY_FILE_MANAGEMENT=AUTO<br />
log_archive_config=&#8217;DG_CONFIG=(PTEST,STEST)&#8217;<br />
LOG_ARCHIVE_DEST_2=&#8217;service=STEST LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=PTEST&#8217;<br />
LOG_ARCHIVE_DEST_STATE_2=DEFER<br />
CONTROL_FILES=(&#8220;/u01/app/oracle/TESTSTANDBY/standby1.ctl&#8221;, &#8220;/u01/app/oracle/TESTSTANDBY/standby2.ctl&#8221;, &#8220;/u01/app/oracle/TESTSTANDBY/standby3.ctl&#8221;)</p>
<p><strong>4.  Configurer le listener, Oracle services names de la base primaire et de la standby</strong></p>
<p>A) Configurer les fichiers $ORACLE_HOME/network/admin/listener.ora pour l&#8217;enregistrement statique</p>
<p><em>listener.ora :</em></p>
<p>SID_LIST_LISTENER_PRIMARY =<br />
(SID_LIST=<br />
(SID_DESC=<br />
(GLOBAL_DBNAME=TEST)<br />
(ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1)<br />
(SID_NAME=PTEST)<br />
)<br />
)</p>
<p>SID_LIST_LISTENER_STANDBY =<br />
(SID_LIST =<br />
(SID_DESC =<br />
(GLOBAL_DBNAME = TEST)<br />
(ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1 )<br />
(SID_NAME = STEST)<br />
)<br />
)</p>
<p>LISTENER_PRIMARY =<br />
(DESCRIPTION_LIST =<br />
(DESCRIPTION =<br />
(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1521))<br />
)<br />
)</p>
<p>LISTENER_STANDBY =<br />
(DESCRIPTION_LIST =<br />
(DESCRIPTION =<br />
(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1522))<br />
)<br />
)</p>
<p>B) Configurer les $ORACLE_HOME/network/admin/tnsnames.ora</p>
<p>STEST =<br />
(DESCRIPTION =<br />
(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1522))<br />
(CONNECT_DATA =<br />
(SERVER = DEDICATED)<br />
(SERVICE_NAME =STEST)<br />
)<br />
)</p>
<p>PTEST =<br />
(DESCRIPTION =<br />
(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1521))<br />
(CONNECT_DATA =<br />
(SERVER = DEDICATED)<br />
(SERVICE_NAME =PTEST)<br />
)<br />
)</p>
<p>C) Redémarrer les listeners des deux bases.</p>
<p>$ORACLE_HOME/bin/lsnrctl start LISTENER_PRIMARY<br />
$ORACLE_HOME/bin/lsnrctl start LISTENER_STANDBY</p>
<p><strong>5. Copie du fichier de mot de passe ou génération avec $ORACLE_HOME/bin/orapwd<br />
</strong></p>
<p><strong>6. Faire un startup mount de la base standby :</strong></p>
<p>SQL&gt; startup mount</p>
<p><strong>7. </strong> <strong>Démarrer le recovery sur la base standby</strong></p>
<p>A l’aide de la commande suivante :<br />
SQL&gt; alter database recover managed standby database disconnect from session;</p>
<ul>
<li>Dès qu’un archive log est transmis par la base primaire, la base standby commence à effectuer le recovery.</li>
<li>L’option “disconnect from session” permet de garder la main sur la session SQL dans laquelle la commande a été exécutée, le process est alors lancé en background.</li>
</ul>
<p><strong> 8.  Vérifier le transport des journaux</strong></p>
<p>En forçant la création d’un archive log sur la base primaire :<br />
SQL&gt; alter system archive log current ;<br />
L’archive log est alors transmis vers le répertoire d’archive de la base standby, et cette dernière fait automatiquement un recovery à partir du log transmis.</p>
<p><strong>9. </strong><strong>Vérifier que le data Guard fonctionne </strong></p>
<p>en exécutant la requête suivante sur le primary et sur la standby:<br />
SQL&gt; select max(sequence#) from v$log_history;</p>
<div style="overflow: hidden; width: 1px; height: 1px;">
<h1><a name="p"></a><span lang="EN-GB"> </span></h1>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal"><em>Remarques :</em></p>
<p class="MsoNormal">
<p class="MsoNormal" style="margin-left: 36pt; text-indent: -18pt;"><!--[if !supportLists]--><span>-<span> </span></span><!--[endif]-->Dans notre démarche nous adopterons la dénomination suivante:</p>
<p class="MsoNormal" style="text-indent: 35.45pt;">PTEST : base primaire</p>
<p class="MsoNormal" style="text-indent: 35.45pt;">STEST : base standby</p>
<p class="MsoNormal" style="margin-left: 36pt; text-indent: -18pt;"><!--[if !supportLists]--><span><span>-<span> </span></span></span><!--[endif]-->Toutes les opérations SQL se font connecté en tant que <strong><em>sys as sysdba</em></strong></p>
<p class="MsoNormal">
<h2><a name="_Toc255820650"></a></h2>
<p class="MsoNormal">
<p class="SQL"><span> </span><span lang="EN-GB">SQL&gt; </span>ALTER DATABASE FORCE LOGGING;</p>
<p class="SQL"><span> </span>SQL&gt; alter database archivelog ;</p>
<blockquote cite="4B94FA71.9070302@capdata.fr">
<h2><a name="_Toc255820651"></a></h2>
<h2><a name="_Toc255820652"></a></h2>
<p class="MsoNormal">
<p class="Titredesection"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Créer les standby controlfile</p>
<p class="MsoNormal">
<p class="SQL"><span> </span><span lang="EN-GB">SQL&gt; alter database create standby controlfile as</span></p>
<p class="SQL"><span lang="EN-GB"><span> </span><span> </span><span> </span>‘/u01/app/oracle/TEST/standby1.ctl’;</span></p>
<p><span lang="EN-GB"> </span></p>
<p class="MsoNormal"><span style="font-size: 10pt;" lang="EN-GB"> </span></p>
<p class="MsoNormal" style="margin-left: 18pt;"><em><span style="font-size: 10pt;" lang="EN-US"> </span></em></p>
<p class="Titredesection" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]--><span lang="EN-US"><span> </span></span>Créer les standby redo log .</p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE</span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>&#8216;/u01/app/oracle/TEST/srl01.log&#8217; SIZE 10M<span> </span>REUSE;</span></p>
<p class="SQL"><span lang="EN-GB"><span> </span></span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE</span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>&#8216;/u01/app/oracle/TEST/srl02.log&#8217; SIZE 10M<span> </span>REUSE;</span></p>
<p class="SQL"><span lang="EN-GB"> </span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE</span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>&#8216;/u01/app/oracle/TEST/srl03.log&#8217; SIZE 10M<span> </span>REUSE;</span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>SQL&gt; ALTER DATABASE ADD STANDBY LOGFILE</span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>&#8216;/u01/app/oracle/TEST/srl04.log&#8217; SIZE 10M<span> </span>REUSE;</span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal"><em><span style="font-size: 10pt;">Il est conseillé de créer un fichier stand by redo log de plus que les redo log afin d’éviter un problème en cas de saturation des redo log</span></em></p>
<p class="MsoNormal"><em><span style="font-size: 10pt;"> </span></em></p>
<p class="Titredesection"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Arrêter la base primaire ((il est possible de le faire à chaud par rman)</p>
<p class="MsoNormal">
<p class="Titredesection" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Faire une copie physique dans un répertoire de sauvegarde des types de fichier suivants :</p>
<p class="MsoNormal">
<p class="MsoNormal" style="margin-left: 53.45pt; text-indent: -18pt;"><!--[if !supportLists]--><span>-<span> </span></span><!--[endif]-->datafiles</p>
<p class="MsoNormal" style="margin-left: 53.45pt; text-indent: -18pt;"><!--[if !supportLists]--><span>-<span> </span></span><!--[endif]-->online redo logs</p>
<p class="MsoNormal" style="margin-left: 53.45pt; text-indent: -18pt;"><!--[if !supportLists]--><span>-<span> </span></span><!--[endif]-->standby controlfile</p>
<p class="MsoNormal" style="margin-left: 53.45pt; text-indent: -18pt;"><!--[if !supportLists]--><span>-<span> </span></span><!--[endif]-->standby redolog</p>
<p class="MsoNormal">
<p class="Titredesection"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Redémarrer la base primaire</p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<h2><a name="_Toc255820653"></a></h2>
<p class="MsoNormal">
<p class="MsoNormal"><span style="text-decoration: underline;">Base ayant le rôle <strong>primaire</strong> (PTEST)</span> :</p>
<div style="border: 1pt solid windowtext; padding: 1pt 4pt;">
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">log_archive_format</span></strong><strong><span lang="EN-GB">=%t_%s_%r.arc</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">log_archive_dest_2</span></strong><strong><span lang="EN-GB">=&#8217;service=STEST LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=STEST&#8217;</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">log_archive_config</span></strong><strong><span lang="EN-GB">=&#8217;DG_CONFIG=(PTEST,STEST)&#8217;</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">LOG_ARCHIVE_DEST_STATE_2</span></strong><strong><span lang="EN-GB">=ENABLE</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">dg_broker_start</span></strong><strong><span lang="EN-GB"> = TRUE</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">db_name=</span></strong><strong><span lang="EN-GB">TEST<span style="color: #f79646;"> </span></span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">db_unique_name</span></strong><strong><span lang="EN-GB">=PTEST</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB"> </span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">### Primary database standby role parameters ###</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">fal_server</span></strong><strong><span lang="EN-GB">=STEST</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">fal_client</span></strong><strong><span lang="EN-GB">=PTEST</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">DB_FILE_NAME_CONVERT</span></strong><strong><span lang="EN-GB">=(&#8216;/u01/app/oracle/TESTSTANDBY&#8217;,'/u01/app/oracle/TEST&#8217;)</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">LOG_FILE_NAME_CONVERT</span></strong><strong><span lang="EN-GB">=(&#8216;/u01/app/oracle/TESTSTANDBY&#8217;,'/u01/app/oracle/TEST&#8217;)</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">standby_archive_dest</span></strong><strong><span lang="EN-GB">=/u01/app/oracle/flash_recovery_area/STEST/standby_archive</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">STANDBY_FILE_MANAGEMENT</span></strong><strong><span lang="EN-GB">=AUTO</span></strong><strong><span> </span></strong></p>
</div>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal"><span style="text-decoration: underline;">Base ayant le rôle <strong>standby</strong> (STEST)</span> :</p>
<p class="MsoNormal">
<p class="MsoNormal">
<div style="border: 1pt solid windowtext; padding: 1pt 4pt;">
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">### Standby database standby role parameters ###</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">fal_server</span></strong><strong><span lang="EN-GB">=PTEST</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">fal_client</span></strong><strong><span lang="EN-GB">=STEST</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">DB_FILE_NAME_CONVERT</span></strong><strong><span lang="EN-GB">=(&#8216;/u01/app/oracle/TEST&#8217;,'/u01/app/oracle/TESTSTANDBY&#8217;)</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">LOG_FILE_NAME_CONVERT</span></strong><strong><span lang="EN-GB">=(&#8216;/u01/app/oracle/TEST&#8217;,'/u01/app/oracle/TESTSTANDBY&#8217;)</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">STANDBY_ARCHIVE_DEST</span></strong><strong><span lang="EN-GB">=/u01/app/oracle/flash_recovery_area/STEST/standby_archive</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">log_archive_format</span></strong><strong><span lang="EN-GB">=%t_%s_%r.dbf</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">STANDBY_FILE_MANAGEMENT</span></strong><strong><span lang="EN-GB">=AUTO</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">log_archive_config</span></strong><strong><span lang="EN-GB">=&#8217;DG_CONFIG=(PTEST,STEST)&#8217;</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB"> </span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">### Standby database primary role parameters ###</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">LOG_ARCHIVE_DEST_2</span></strong><strong><span lang="EN-GB">=&#8217;service=STEST LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=PTEST&#8217;</span></strong></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><strong><span lang="EN-GB">LOG_ARCHIVE_DEST_STATE_2</span></strong><strong><span lang="EN-GB">=DEFER</span></strong><strong><span> </span></strong></p>
</div>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">
<h2><a name="_Toc255820654"></a></h2>
<p class="MsoNormal">
<p class="Titredesection" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Configurer les fichiers listener.ora situés sous $ORACLE_HOME/network/admin</p>
<p class="MsoNormal">
<p class="MsoNormal" style="margin-left: 18pt;"><span>Si le port du <em>listener</em> de l’instance n’est pas 1521, la valeur du paramètre LOCAL_LISTENER doit être renseignée.</span></p>
<p class="MsoNormal">
<p class="MsoNormal"><span lang="EN-US">Listener.ora</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<div style="border: 1pt solid windowtext; padding: 1pt 4pt;">
<p><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">SID_LIST_LISTENER_PRIMARY =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_LIST=</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_DESC=</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span><span> </span>(GLOBAL_DBNAME=TEST)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_NAME=PTEST)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">SID_LIST_LISTENER_STANDBY =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_LIST =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span></span><span>(SID_DESC =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_NAME = PLSExtProc)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(PROGRAM = extproc)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_DESC =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(GLOBAL_DBNAME = TEST)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1 )</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID_NAME = STEST)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span></span><span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">LISTENER_PRIMARY =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(DESCRIPTION_LIST =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(DESCRIPTION =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1521))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">LISTENER_STANDBY =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">(DESCRIPTION_LIST =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(DESCRIPTION =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC2))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1522))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span></span><span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span><span> </span>)</span></p>
</div>
<p class="MsoNormal">
<p class="Titredesection" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Configurer les tnsnames.ora</p>
<div style="border: 1pt solid windowtext; padding: 1pt 4pt;">
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">STEST =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(DESCRIPTION =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1522))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(CONNECT_DATA =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SERVER = DEDICATED)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span><span> </span>(SERVICE_NAME =STEST)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">PTEST =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(DESCRIPTION =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = TCP)(HOST = LINUX-ORA10-DATAGUARD-PRIMARY)(PORT = 1521))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(CONNECT_DATA =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SERVER = DEDICATED)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SERVICE_NAME =PTEST)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US">EXTPROC_CONNECTION_DATA =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(DESCRIPTION =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS_LIST =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(CONNECT_DATA =</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(SID = PLSExtProc)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span>(PRESENTATION = RO)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span lang="EN-US"><span> </span></span><span>)</span></p>
<p class="MsoNormal" style="border: medium none; padding: 0cm;"><span><span> </span>)</span></p>
</div>
<p class="MsoNormal">
<p class="MsoNormal">Redémarrer les listeners des deux bases.</p>
<p class="MsoNormal">
<p class="MsoNormal"><span lang="EN-US">&gt;Lsnrctl start LISTENER_PRIMARY</span></p>
<p class="MsoNormal"><span lang="EN-US">&gt;Lsnrctl start LISTENER_STANDBY</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<h2><a name="_Toc255820655"></a></h2>
<p class="MsoNormal">
<p class="SQL"><span lang="EN-GB">SQL&gt; create spfile from pfile=’/u01/app/oracle/admin/PTEST/pfileinitGUARD2.ora’ ;</span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="Titredesection"><!--[if !supportLists]--><span style="font-family: Symbol;"> </span><!--[endif]-->Faire un startup nomount de la base standby, puis la monter en mode standby:</p>
<p class="MsoNormal">
<p class="SQL"><span> </span><span lang="EN-US">SQL&gt; startup nomount</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="SQL"><span lang="EN-GB"><span> </span>SQL&gt; alter database mount standby database ;</span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal">
<h2><a name="_Toc255820656"></a></h2>
<p class="MsoNormal">
<p class="PucesLBi"><!--[if !supportLists]--><span style="font-family: Wingdings; color: #3366ff;"><span>§<span> </span></span></span><!--[endif]-->A l’aide de la commande suivante :</p>
<p class="MsoNormal">
<p class="SQL" style="margin-left: 35.45pt;"><span lang="EN-GB">SQL&gt; alter database recover managed standby database disconnect from session;</span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="PucesLBi" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Wingdings; color: #3366ff;"><span>§<span> </span></span></span><!--[endif]-->Dès qu’un archive log est transmis par la base primaire, la base standby commence à effectuer le recovery.</p>
<p class="MsoNormal">
<p class="PucesLBi" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Wingdings; color: #3366ff;"><span>§<span> </span></span></span><!--[endif]-->L’option “disconnect from session” permet de garder la main sur la session SQL dans laquelle la commande a été exécutée, le process est alors lancé en background.</p>
<p class="MsoNormal" style="margin-left: 18pt;">
<p class="PucesLBi" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Wingdings; color: #3366ff;"><span>§<span> </span></span></span><!--[endif]-->Démarrer le transport des redo logs en forçant la création d’un archive log sur la base primaire :</p>
<p class="MsoNormal" style="margin-left: 18pt;">
<p class="SQL"><span> </span><span lang="EN-US">SQL&gt; alter system archive log current ;</span></p>
<p class="MsoNormal" style="margin-left: 18pt;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: justify;">L’archive log est alors transmis vers le répertoire d’archive de la base standby, et cette dernière fait automatiquement un recovery à partir du log transmis.</p>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="PucesLBi" style="text-align: justify;"><!--[if !supportLists]--><span style="font-family: Wingdings; color: #3366ff;"><span>§<span> </span></span></span><!--[endif]-->Vérifier que le dataguard fonctionne en exécutant la requête suivante <span style="text-decoration: underline;">sur le primary et sur la standby</span>:</p>
<p class="MsoNormal" style="margin-left: 18pt;">
<p class="SQL"><span> </span><span lang="EN-US">SQL&gt; select max(sequence#) from v$log_history;</span></p>
</blockquote>
</div>
<p><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/" rel="bookmark" title="5 juin 2009">Installation Oracle 64 bits sur Red Hat 5</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-direct-io-dsync-onoff-raw-device/" rel="bookmark" title="18 juin 2009">Direct i/o, dsync on/off, raw device</a> (David BAFFALEUF) [Sybase]</li>
<li><a href="http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.754 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%2Fcreation-d%25e2%2580%2599une-physical-standby-database%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fcreation-d%25e2%2580%2599une-physical-standby-database%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/IgU8YhKCJG8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/</feedburner:origLink></item>
		<item>
		<title>Installation Oracle 11gR2 64 bits sur Red Hat 5 Partie 1</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/Le0E0krJRFs/</link>
		<comments>http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 16:41:04 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[11gR2]]></category>
		<category><![CDATA[asm]]></category>
		<category><![CDATA[Grid]]></category>
		<category><![CDATA[Red Hat]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=654</guid>
		<description><![CDATA[Cet article est écrit par Thierry GASCARD.
Il sera composé de trois parties :
- installation Oracle Grid Infrastructure 11gR2
- installation Oracle Database 11gR2
- utilisation Oracle Restart
1.  Configuration système
1.1 Pré-requis matériel :
-  5 Go pour les binaires Oracle en RAID 10
-  400 Mo sur /tmp
-  disques pour ASM
1.2 Noyau linux utilisé
RH 5 Entreprise 64 Bits Update 4
1.3 [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est écrit par Thierry GASCARD.<br />
Il sera composé de trois parties :<br />
- installation Oracle Grid Infrastructure 11gR2<br />
- installation Oracle Database 11gR2<br />
- utilisation Oracle Restart</p>
<p><strong>1.  Configuration système</strong></p>
<p>1.1 Pré-requis matériel :</p>
<p>-  5 Go pour les binaires Oracle en RAID 10<br />
-  400 Mo sur /tmp<br />
-  disques pour ASM</p>
<p>1.2 Noyau linux utilisé</p>
<p>RH 5 Entreprise 64 Bits Update 4</p>
<p>1.3 Pré-requis noyau</p>
<p>SELinux désactivé<br />
X installé et configuré<br />
Rpms suivants installés en plus des Rpms par défaut (version minimum) :<br />
binutils-2.17.50.0.6-12.el5  (x86_64)<br />
compat-libstdc++-33-3.2.3-61  (x86_64)<br />
compat-libstdc++-33-3.2.3-61  (i386)<br />
elfutils-libelf-0.137-3.el5  (x86_64)<br />
elfutils-libelf-0.137-3.el5  (i386)<br />
elfutils-libelf-devel-0.137-3.el5  (i386)<br />
elfutils-libelf-devel-0.137-3.el5  (x86_64)<br />
elfutils-libelf-devel-static-0.137-3.el5  (i386)<br />
elfutils-libelf-devel-static-0.137-3.el5  (x86_64)<br />
gcc-4.1.2-46.el5  (x86_64)<br />
gcc-c++-4.1.2-46.el5  (x86_64)<br />
glibc-2.5-42  (i686)<br />
glibc-2.5-42  (x86_64)<br />
glibc-common-2.5-42  (x86_64)<br />
glibc-devel-2.5-42  (x86_64)<br />
glibc-devel-2.5-42  (i386)<br />
glibc-headers-2.5-42  (x86_64)<br />
ksh-20080202-14.el5  (x86_64)<br />
libaio-0.3.106-3.2  (x86_64)<br />
libaio-0.3.106-3.2  (i386)<br />
libaio-devel-0.3.106-3.2  (i386)<br />
libaio-devel-0.3.106-3.2  (x86_64)<br />
libgcc-4.1.2-46.el5  (x86_64)<br />
libgcc-4.1.2-46.el5  (i386)<br />
libstdc++-4.1.2-46.el5  (x86_64)<br />
libstdc++-4.1.2-46.el5  (i386)<br />
libstdc++-devel-4.1.2-46.el5  (x86_64)<br />
libstdc++-devel-4.1.2-46.el5  (i386)<br />
make-3.81-3.el5  (x86_64)<br />
sysstat-7.0.2-3.el5  (x86_64)<br />
unixODBC-2.2.11-7.1  (x86_64)<br />
unixODBC-2.2.11-7.1  (i386)<br />
unixODBC-devel-2.2.11-7.1  (x86_64)<br />
unixODBC-devel-2.2.11-7.1  (i386)</p>
<p>La commande suivante nous donne des informations sur les Rpms nécessaires :<br />
rpm -q &#8211;qf &#8216;%{NAME}-%{VERSION}-%{RELEASE}  (%{ARCH})\n&#8217; \<br />
binutils compat-libstdc++-33-3.2.* elfutils-libelf elfutils-libelf-devel \<br />
elfutils-libelf-devel-static gcc gcc-c++ glibc glibc-common glibc-devel glibc-headers \<br />
ksh libaio libaio-devel libgcc libstdc++ libstdc++-devel make sysstat unixODBC unixODBC-devel</p>
<p>Rem : attention à la présence de rpms 32 bits : utilisation possible de l’option force : rpm -ivh –force ..</p>
<p>1.4 Configuration des limites systèmes</p>
<p>[root@]# cat &gt;&gt; /etc/security/limits.conf &lt;&lt;EOF<br />
grid soft nproc 2047<br />
grid hard nproc 16384<br />
grid soft nofile 1024<br />
grid hard nofile 65536<br />
EOF</p>
<p>[root@]# cat &gt;&gt; /etc/pam.d/login &lt;&lt;EOF<br />
session    required     pam_limits.so<br />
EOF</p>
<p>[root@]# cat &gt;&gt; /etc/profile &lt;&lt;EOF<br />
if [ \$USER = "oracle" ] || [ \$USER = "grid" ]; then<br />
if [ \$SHELL = "/bin/ksh" ]; then<br />
ulimit -p 16384<br />
ulimit -n 65536<br />
ulimit -n 25165824<br />
else<br />
ulimit -u 16384 -n 65536 -l 25165824<br />
fi<br />
umask 022<br />
fi<br />
EOF</p>
<p>1.5 Configuration du serveur pour oracle</p>
<p>[root@]# cat &gt;&gt; /etc/sysctl.conf &lt;&lt;EOF<br />
kernel.shmmax=25769803776 &#8212; soit 24 Go<br />
kernel.shmall=6291456 &#8212; avec taille de 4ko soit 24 Go<br />
kernel.shmmni = 4096<br />
kernel.sem = 250 32000 100 128<br />
fs.file-max = 6815744<br />
net.ipv4.ip_local_port_range = 9000 65500<br />
net.core.rmem_default=262144<br />
net.core.rmem_max=4194304<br />
net.core.wmem_default=262144<br />
net.core.wmem_max=1048576<br />
fs.aio-max-nr=1048576<br />
EOF</p>
<p><strong>2.   Préparation système</strong></p>
<p>2.1 Création groupe oinstall,asmadmin,asmdba,asmoper</p>
<p>[root@]# groupadd -g 1000 oinstall<br />
[root@]# groupadd -g 1200 asmadmin<br />
[root@]# groupadd -g 1201 asmdba<br />
[root@]# groupadd -g 1202 asmoper</p>
<p>2.2   Création utilisateur grid</p>
<p>[root@]# useradd -m -u 1100 -g oinstall -G asmadmin,asmdba,asmoper -d /home/grid -s /bin/bash -c &#8220;Grid Infrastructure Owner&#8221; grid<br />
[root@]# id grid<br />
[root@]# passwd grid</p>
<p>2.3 Vérification de l&#8217;existence de l&#8217;utilisateur nobody</p>
<p>[root@]# id nobody</p>
<p>2.4    Création des répertoires</p>
<p>[root@]# mkdir -p /capdata/app/grid<br />
[root@]# mkdir -p /capdata/app/11.2.0/grid<br />
[root@]# chown -R grid:oinstall /capdata<br />
[root@]# chmod -R 775 /capdata</p>
<p>2.4 Mise à jour du profile de l&#8217;utilisateur grid</p>
<p>export ORACLE_SID=+ASM<br />
export ORACLE_BASE=/capdata/app/grid<br />
export ORACLE_HOME=/capadata/app/11.2.0/grid<br />
export ORA_NLS11=$ORACLE_HOME/nls/data<br />
export PATH=${PATH}:$HOME/bin:$ORACLE_HOME/bin<br />
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/oracm/lib<br />
export CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib:$ORACLE_HOME/network/jlib<br />
export TEMP=/tmp<br />
export TMPDIR=/tmp<br />
umask 022</p>
<p><strong>3. Installation et configuration de la librairie ASM</strong><br />
3.1   Téléchargement</p>
<p>En fonction du noyau linux (uname -r), télécharger les rpms ASM sur le site <a href="http://www.oracle.com/technology/tech/linux/asmlib/" target="_blank">Oracle d&#8217;asm </a><br />
- ASMLib Kernel Driver<br />
- Userspace Library<br />
- Driver Support Files</p>
<p>3.2   Installation</p>
<p>[root@]#rpm -Uvh oracleasm*</p>
<p>3.2   Configuration</p>
<p>[root@]# /usr/sbin/oracleasm configure -i<br />
..<br />
Default user to own the driver interface []: <strong>grid</strong><br />
Default group to own the driver interface []: <strong>asmadmin</strong><br />
Start Oracle ASM library driver on boot (y/n) [n]: <strong>y</strong><br />
Scan for Oracle ASM disks on boot (y/n) [y]: <strong>y</strong><br />
Writing Oracle ASM library driver configuration: done</p>
<p>puis chargement<br />
[root@]# /usr/sbin/oracleasm init</p>
<p>3.2   Création des disques ASM<br />
a &#8211; partitionnement des LUNs EMC</p>
<p>J&#8217;effectue un alignement des partitions en enlevant les 256 premiers secteurs de disques soit 128 Ko</p>
<p>[root@]# /sbin/parted /dev/emcpowera<br />
mklabel msdos<br />
unit s<br />
mkpart primary 256 -1s<br />
print<br />
quit</p>
<p>[root@]# /sbin/parted /dev/emcpowerb<br />
mklabel msdos<br />
unit s<br />
mkpart primary 256 -1s<br />
print<br />
quit</p>
<p>b- création des disques ASM</p>
<p>[root@]# /usr/sbin/oracleasm createdisk DATA_DISK1 /dev/emcpowera1<br />
[root@]# /usr/sbin/oracleasm createdisk BACK_DISK1 /dev/emcpowerb1</p>
<p><strong>4. Installation d&#8217;Oracle Grid Infrasture 11gR2</strong></p>
<p>[grid@]# ./runInstaller &amp;</p>
<p>Ordre d’installation<br />
1. Installation Option : « Install and Configure for Standalone Server »<br />
2. Product Languages : « english, french »<br />
3. Create ASM Disk Group : « DATA,BACK »<br />
4. ASM passwaord  : «same password»<br />
5. Operating system Group : « asmdba,asmoper,asmadmin »<br />
6. Installation location :<br />
ORACLE_BASE : /capdata/app/grid<br />
ORACLE_HOME : /capadata/app/11.2.0/grid<br />
7. Prerequisite checks :<br />
Génération d&#8217;un script fixit.sh pour fixer d&#8217;événtuel problème<br />
8. Summary<br />
9. Setup<br />
Lancement de deux scripts sous root<br />
[root@]# /capdata/app/oraInventory/orainstRoot.sh<br />
[root@]# /capdata/app/11.2.0/grid/root.sh<br />
10.Finish</p>
<p>Et voilà pour la première partie&#8230;.<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/" rel="bookmark" title="5 juin 2009">Installation Oracle 64 bits sur Red Hat 5</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/" rel="bookmark" title="12 juin 2008">Se connecter à SQL Server à travers Oracle, quelle drôle d&#8217;idée ?</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/" rel="bookmark" title="5 juin 2009">Création et utilisation d&#8217;OCFS2</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/utiliser-asmcmd/" rel="bookmark" title="5 juin 2009">Utiliser ASMCMD</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 4.097 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%2Finstallation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Finstallation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/Le0E0krJRFs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/</feedburner:origLink></item>
		<item>
		<title>SQLDIAG (épisode 1)</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/g4fNSCuitYM/</link>
		<comments>http://blog.capdata.fr/index.php/sqldiag-episode-1/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 12:10:31 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[perfmon]]></category>
		<category><![CDATA[pssdiag]]></category>
		<category><![CDATA[RML Utilities]]></category>
		<category><![CDATA[sqldiag]]></category>
		<category><![CDATA[SQLNexus]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=490</guid>
		<description><![CDATA[Début d&#8217;une assez longue série de posts sur l&#8217;utilitaire SQLDIAG et ses petits camarades de jeu PSSDIAG, SQLNexus et autres RML Utilities&#8230;
SQLDIAG est un utilitaire en mode ligne de commandes qui est livré avec SQL Server depuis plus de 10 ans maintenant. Il est bien caché, peu de gens l&#8217;utilisent mais il peut être d&#8217;une [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #333333;">Début d&#8217;une assez longue série de posts sur l&#8217;utilitaire SQLDIAG et ses petits camarades de jeu PSSDIAG, SQLNexus et autres RML Utilities&#8230;</span></p>
<p><span style="color: #333333;"><strong>SQLDIAG </strong>est un utilitaire en mode ligne de commandes qui est livré avec SQL Server depuis plus de 10 ans maintenant. Il est bien caché, peu de gens l&#8217;utilisent mais il peut être d&#8217;une puissance redoutable. Il est capable de lancer en même temps:</span></p>
<ul>
<li><span style="color: #333333;"><em>Une collecte perfmon.</em></span></li>
<li><span style="color: #333333;"><em>Une trace type SQL Trace.</em></span></li>
<li><span style="color: #333333;"><em>Une collecte des journaux d&#8217;évènements.</em></span></li>
<li><span style="color: #333333;"><em>Un inventaire complet  de la machine basé sur msinfo32.</em></span></li>
<li><span style="color: #333333;"><em>Un inventaire complet de l&#8217;instance.</em></span></li>
</ul>
<p><span style="color: #333333;">Il permettra même de corréler des traces de compteurs perfmon et le traçage de sessions SQL dans Profiler. Il se base sur un fichier de configuration au format XML. Il en existe un par défaut (SQLDiag.xml) qui se trouve sous ~Tools\Binn, mais il est très exhaustif  et trace tous les compteurs et évènements disponibles. L&#8217;inconvénient de l&#8217;utiliser est qu&#8217;il créé des traces pénalisantes et très encombrantes, plusieurs dizaines de Gb de fichiers textes, blg, trc, etc&#8230; Donc on a intérêt à se créer son petit fichier XML pour ne capturer que ce dont on aura besoin.</span></p>
<h2><span style="color: #333333;">SQLDiag.xml<br />
</span></h2>
<p><span style="color: #333333;">Dans ce premier épisode, nous allons donc parler de la structure de ce fichier XML. Elle ressemble vu d&#8217;en haut à ceci:</span></p>
<pre><span style="color: #0000ff;">&lt;Collection&gt;
&lt;Machines&gt;
        &lt;Machine name="."&gt;
                &lt;MachineCollectors&gt;
                        &lt;<span style="color: #008000;">EventlogCollector</span> /&gt;
                        &lt;<span style="color: #008000;">PerfmonCollector</span> /&gt;
                &lt;/MachineCollectors&gt;
                &lt;Instances&gt;
                       &lt;Instance&gt;
                              &lt;Collectors&gt;
                                    &lt;<span style="color: #008000;">SqldiagCollector</span> /&gt;
                                    &lt;<span style="color: #008000;">BlockingCollector</span> /&gt;
                                    &lt;<span style="color: #008000;">ProfilerCollector</span> /&gt;
                                    &lt;<span style="color: #008000;">CustomDiagnostics</span> /&gt;
                             &lt;/Collectors&gt;
                     &lt;/Instance&gt;
              &lt;/Instances&gt;
      &lt;/Machine&gt;
&lt;/Machines&gt;
&lt;/Collection&gt;</span></pre>
<p><span style="color: #000000;"><span style="color: #333333;">Chaque balise </span><span style="color: #008000;"><strong>%</strong><em><strong>Collector</strong></em><span style="color: #333333;"> </span></span><span style="color: #333333;">délimite la zone de paramétrage de chaque <strong>collecteur de trace</strong>. Pour activer / désactiver un collecteur, passer son attribut enabled à <em>true</em> ou <em>false</em>:</span></span></p>
<ul>
<li><span style="color: #333333;"><strong>EventlogCollector </strong>pour collecter les journaux d&#8217;évènements.<br />
</span></li>
<li><span style="color: #333333;"><strong>PerfmonCollector </strong>pour lancer la trace perfmon.</span></li>
<li><span style="color: #333333;"><strong>SQLdiagCollector </strong>pour récupérer toute la configuration de l&#8217;instance: paramètres, contenu de tous les errorlogs, connexions, verrous, liste des bases et options, xp_msver, etc&#8230;<br />
</span></li>
<li><span style="color: #333333;"><strong>BlockingCollector </strong>pour l&#8217;évènement BlockedProcessReport de SQL Trace, rapporte les processus bloqués si le paramètre &#8216;<em>blocked process threshold (s)</em>&#8216; est configuré.</span></li>
<li><span style="color: #333333;"><strong>ProfilerCollector </strong>pour la trace SQL Trace complète avec les évènements que l&#8217;on aura indiqué.<br />
</span></li>
<li><span style="color: #333333;"><strong>CustomDiagnostics </strong>pour lancer des exécutables supplémentaires, en l&#8217;occurence msinfo32 dans notre cas, et récupérer la configuration complète de la machine.<br />
</span></li>
</ul>
<h3><span style="color: #333333;"><strong>PerfmonCollector </strong></span></h3>
<p><span style="color: #333333;">C&#8217;est le collecteur de compteurs perfmon. Ses éléments fils sont &lt;PerfmonObject /&gt; qui désigne la famille de compteurs comme <em>&#8220;PhysicalDisk(*)</em>&#8221; par exemple, et &lt;PerfmonCounter /&gt; qui désigne le compteur associé comme &#8220;<em>\Avg. Disk sec/Read</em>&#8220;. On aura besoin d&#8217;activer chaque compteur en passant son attribut enabled à <em>true</em>. Une zone PerfmonCollector peut ressembler à ceci, avec le nom des compteurs en vert:</span></p>
<pre><span style="color: #0000ff;">&lt;PerfmonCollector enabled="true" pollinginterval="30" maxfilesize="256"&gt;
    &lt;PerfmonCounters&gt;
        &lt;PerfmonObject name="\PhysicalDisk(*)" enabled="true"&gt;
             &lt;PerfmonCounter name="<span style="color: #008000;">\Avg. Disk sec/Read</span>" enabled="true" /&gt;
             &lt;PerfmonCounter name="<span style="color: #008000;">\Avg. Disk sec/Write</span>" enabled="true" /&gt;
             &lt;PerfmonCounter name="<span style="color: #008000;">\Disk Read Bytes/sec</span>" enabled="true" /&gt;
             &lt;PerfmonCounter name="<span style="color: #008000;">\Disk Write Bytes/sec</span>" enabled="true" /&gt;
             &lt;PerfmonCounter name="<span style="color: #008000;">\Avg. Disk Bytes/Transfer</span>" enabled="true" /&gt;
        &lt;/PerfmonObject&gt;
        &lt;PerfmonObject name="\Processor(*)" enabled="true"&gt;
            &lt;PerfmonCounter name="<span style="color: #008000;">\% Processor Time</span>" enabled="true" /&gt;
            &lt;PerfmonCounter name="<span style="color: #008000;">\% User Time</span>" enabled="true" /&gt;
            &lt;PerfmonCounter name="<span style="color: #008000;">\% Privileged Time</span>" enabled="true" /&gt;
        &lt;/PerfmonObject&gt;
    &lt;/PerfmonCounters&gt;
&lt;/PerfmonCollector&gt;</span></pre>
<p><span style="color: #333333;">L&#8217;attribut <em>pollinginterval </em>indique la fréquence d&#8217;échantillonnage des compteurs. Le fichier de sortie de ce collecteur sera un fichier BLG intitulé tout simplement<em> <strong>SQLDIAG.blg</strong></em>. Il pourra être corrélé plus tard avec la trace qui sera générée par le collecteur ProfilerCollector.</span></p>
<h3><span style="color: #333333;">SQLdiagCollector</span></h3>
<p><span style="color: #333333;">C&#8217;est le collecteur de données de l&#8217;instance. Il n&#8217;est pas paramétrable est composé d&#8217;une seule ligne:</span></p>
<pre><span style="color: #0000ff;">&lt;SqldiagCollector enabled="true" startup="false" shutdown="true" /&gt; </span></pre>
<p><span style="color: #333333;">On l&#8217;activera donc en passant son attribut enabled à <em>true</em> là encore. Les paramètres startup et shutdown permettent d&#8217;indiquer si la collecte se fait au démarrage ou à l&#8217;arrêt de la trace SQLDIAG.<br />
</span></p>
<h3><span style="color: #333333;">BlockingCollector:</span></h3>
<p><span style="color: #333333;">C&#8217;est le collecteur des processus bloqués en attente de libération de ressources (verrous). Lui aussi n&#8217;est constitué  que d&#8217;un seul élément:</span></p>
<pre><span style="color: #0000ff;">&lt;BlockingCollector enabled="true" pollinginterval="5" maxfilesize="350" /&gt; </span></pre>
<p><span style="color: #333333;">L&#8217;attribut <em>pollinginterval </em>désigne la fréquence d&#8217;échantillonnage  de l&#8217;évènement, et <em>maxfilesize </em>la taille maximale du fichier en sortie. Ce collecteur se base sur le paramètre d&#8217;instance &#8216;<em>blocked process threshold</em>&#8216; qui définit la durée en secondes au delà de laquelle on considère que le blocage est anormalement long. Il faudra définir ce paramètre car sa valeur par défaut est à zéro, ce qui signifie qu&#8217;il n&#8217;est pas activé. Par exemple pour mettre le seuil à 20 secondes:</span></p>
<pre><span style="color: #808080;">sp_configure 'blocked process threshold', 20
go
reconfigure
go</span></pre>
<p><span style="color: #333333;">Ensuite, le collecteur va créer une trace SQL Trace avec le seul évènement &#8216;<em>Blocked Process Report</em>&#8216;, et capturer les sessions qui auront été bloquées pendant plus de 20 secondes. Le fichier de sortie de ce collecteur est un fichier trc classique nommé <strong><em>&lt;INSTANCE&gt;_SQLDIAG_sp_trace_blk</em></strong>.</span></p>
<h3><span style="color: #333333;">ProfilerCollector:</span></h3>
<p><span style="color: #333333;">Ensuite, ProfilerCollector est le collecteur de trace SQL Trace classique. Comme pour PerfmonCollector, il va disposer d&#8217;éléments fils comme &lt;EventType /&gt; et &lt;Event /&gt; dans lesquels on va bien entendu retrouver nos classes d&#8217;évènements:</span></p>
<pre><span style="color: #0000ff;">&lt;ProfilerCollector enabled="true" template="_GeneralPerformance100.xml" pollinginterval="5" maxfilesize="350"&gt;
     &lt;Events&gt;
         &lt;EventType name="Stored Procedures"&gt;
             &lt;Event id="10" name="<span style="color: #008000;">RPC:Completed<span style="color: #0000ff;">"</span><span style="color: #0000ff;"> enabled="true</span></span>"/&gt;
             &lt;Event id="11" name="<span style="color: #008000;">RPC:Starting<span style="color: #0000ff;">"</span><span style="color: #0000ff;"><span style="color: #0000ff;"> </span>enabled="true</span></span><span style="color: #0000ff;">"</span> /&gt;
             &lt;Event id="43" name="<span style="color: #008000;">SP:Completed</span>" enabled="true" /&gt;
             &lt;Event id="42" name="<span style="color: #008000;">SP:Starting</span>" enabled="true" /&gt;
             &lt;Event id="45" name="<span style="color: #008000;">SP:StmtCompleted</span>" enabled="true" /&gt;
             &lt;Event id="44" name="<span style="color: #008000;">SP:StmtStarting</span>" enabled="true" /&gt;
        &lt;/EventType&gt;
       &lt;EventType name="TSQL"&gt;
             &lt;Event id="40" name="<span style="color: #008000;">SQL:StmtStarting</span>" enabled="true"/&gt;
             &lt;Event id="41" name="<span style="color: #008000;">SQL:StmtCompleted</span>" enabled="true" /&gt;
       &lt;/EventType&gt;
     &lt;/Events&gt;
 &lt;/ProfilerCollector&gt;</span></pre>
<p><span style="color: #333333;">Le fichier de sortie de ce collecteur sera </span>aussi <span style="color: #333333;">un fichier trace classique nommé </span><strong><em>&lt;INSTANCE&gt;_SQLDIAG_sp_trace.</em></strong></p>
<h3><span style="color: #333333;">CustomDiagnostics</span></h3>
<p>Enfin, CustomDiagnostics permet de pousser encore plus loin la personnalisation du rapport, en nous permettant d&#8217;utiliser nos propres outils de collecte. L&#8217;outil qui est utilisé par défaut est <strong>msinfo32 </strong>qui est utilisé pour afficher de manière graphique (Démarrer -&gt; Exécuter -&gt; msinfo32) ou en ligne de commande toute la configuration de la machine hôte:</p>
<pre><span style="color: #0000ff;">&lt;CustomDiagnostics&gt;
 &lt;CustomGroup name="msinfo" enabled="true" /&gt;
 &lt;CustomTask enabled="true" groupname="MsInfo" taskname="<span style="color: #008000;">Get MSINFO32</span>" type="Utility" point="Startup" wait="OnlyOnShutdown" cmd="start /B /WAIT MSInfo32.exe /computer %server% /report
         &amp;quot;%output_path%%server%_MSINFO32.TXT&amp;quot; /categories +SystemSummary+ResourcesConflicts+ResourcesIRQS+ComponentsNetwork+ComponentsStorage+ComponentsProblemDevices+SWEnvEnvVars+
         SWEnvNetConn+SWEnvServices+SWEnvProgramGroup+SWEnvStartupPrograms" /&gt;
 &lt;CustomTask enabled="true" groupname="MsInfo" taskname="<span style="color: #008000;">Get default traces</span>" type="Copy_File" point="Startup" wait="OnlyOnShutdown" cmd="&amp;quot;%sspath%log\log*.trc&amp;quot; &amp;quot;%output_path%&amp;quot;" /&gt;
 &lt;CustomTask enabled="true" groupname="MsInfo" taskname="<span style="color: #008000;">Get SQLDumper log</span>" type="Copy_File" point="Startup" wait="OnlyOnShutdown" cmd="&amp;quot;%sspath%log\SQLDUMPER_ERRORLOG.log&amp;quot;
          &amp;quot;%output_path%%server%_%instance%_SQLDUMPER_ERRORLOG.log&amp;quot;" /&gt;
 &lt;/CustomDiagnostics&gt;</span></pre>
<p>Mais en plus de récupérer le contenu d&#8217;une trace msinfo32, il peut également récupérer le contenu des traces SQL Server par défaut *, et les stacktraces générées par SQL Server lorsqu&#8217;il rencontre une erreur fatale sur un module. Il va copier le contenu de ces traces dans le répertoire passé à l&#8217;exécution de SQLDIAG.</p>
<h2>Exécution d&#8217;une trace</h2>
<p>Une fois le fichier XML défini, lancer une trace devient un jeu d&#8217;enfant:</p>
<pre><strong>$ sqldiag /I MyXMLfile.xml /O e:/SQLDIAG/TRACE1</strong>
<span style="color: #808080;">2010/02/04 18:58:10.28 SQLDIAG Collector version
2010/02/04 18:58:10.29 SQLDIAG</span>

<span style="color: #008000;">IMPORTANT:  Please wait until you see "Collection started" before attempting to reproduce your issue</span>

<span style="color: #808080;">2010/02/04 18:58:10.29 SQLDIAG Output path: e:\SQLDIAG\TRACE1\
2010/02/04 18:58:10.33 SQLDIAG Collecting from 1 logical machine(s)
2010/02/04 18:58:10.34 SQLDIAG Invalid node fetched. (null)
2010/02/04 18:58:10.34 SQLDIAG Invalid node fetched. (null)
2010/02/04 18:58:10.34 MS2K8-WIN2008-1\* SQL Server version: 10
2010/02/04 18:58:10.35 MS2K8-WIN2008-1\* Machine name: MS2K8-WIN2008-1 (this machine)
2010/02/04 18:58:10.35 MS2K8-WIN2008-1\* Target machine is not a cluster
2010/02/04 18:58:10.35 MS2K8-WIN2008-1\* Instance: (Default) (32-bit)
2010/02/04 18:58:12.40 SQLDIAG Initialization starting...
2010/02/04 18:58:13.98 MS2K8-WIN2008-1\* Starting Profiler trace
2010/02/04 18:58:14.94 MS2K8-WIN2008-1\* Starting Blocking script
2010/02/04 18:58:16.88 MS2K8-WIN2008-1\* MsInfo: Get MSINFO32
2010/02/04 18:58:17.26 MS2K8-WIN2008-1\* MsInfo: Get default traces
2010/02/04 18:58:17.47 MS2K8-WIN2008-1\* MsInfo: Get SQLDumper log
2010/02/04 18:58:17.71 MS2K8-WIN2008-1\* Adding Perfmon counters...
2010/02/04 18:58:20.73 MS2K8-WIN2008-1\* Starting Perfmon
2010/02/04 18:58:20.73 SQLDIAG Initialization complete
2010/02/04 18:58:21.53 MS2K8-WIN2008-1\* Perfmon started
2010/02/04 18:58:21.58 MS2K8-WIN2008-1\* Collecting diagnostic data</span>

<span style="color: #008000;">2010/02/04 18:58:22.28 SQLDIAG Collection started.  Press Ctrl+C to stop.</span></pre>
<p>La trace est lancée, un simple Ctrl-C suffira à la stopper. Les commutateurs /I et /O permettent d&#8217;indiquer le fichier de configuration XML choisi et le répertoire où va se loger le contenu de la trace complète.</p>
<p>Il existe aussi des commutateurs pour indiquer à SQLDIAG de programmer son exécution à des heures déterminées. Il est même possible de l&#8217;enregistrer en tant que service dans windows.</p>
<p>Dans le prochain post sur SQLDIAG, on verra comment dépouiller les fichiers de résultat.</p>
<p>A+ David B.</p>
<p>(avec la collaboration de Martial LUCAS. )</p>
<p><em>* Depuis la version SQL Server 2005, un paramètre instance &#8216;default trace enabled&#8217; avec une valeur de 1 (valeur par défaut) génère une trace systématiquement au démarrage de l&#8217;instance. Cette trace contient les classes évènements Database, Errors and Warnings, Full text, Objects, Performance, Server et Security Audit. Chaque trace vient se loger dans le répertoire des ERRORLOG par défaut.</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/utiliser-asmcmd/" rel="bookmark" title="5 juin 2009">Utiliser ASMCMD</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/" rel="bookmark" title="13 juin 2008">Modes de récupération et journal de transactions, épisode 1</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/sqldiag-episode-2/" rel="bookmark" title="10 mai 2010">SQLDIAG (épisode 2)</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 27.500 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%2Fsqldiag-episode-1%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsqldiag-episode-1%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/g4fNSCuitYM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sqldiag-episode-1/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sqldiag-episode-1/</feedburner:origLink></item>
		<item>
		<title>Retrouver les tables dont les stats ne sont plus compilées en automatique</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/Xbgl-2q-TQQ/</link>
		<comments>http://blog.capdata.fr/index.php/sql-server-retrouver-les-tables-dont-les-stats-ne-sont-plus-compilees-en-automatique/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 17:09:28 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[statistiques]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=452</guid>
		<description><![CDATA[Quand on tombe sur un problème de performance de requête, il faut entre autres choses vérifier si les statistiques sur les tables ont bien été recompilées récemment. En effet, ce n&#8217;est pas parce que les options &#8216;auto create statistics&#8216; et &#8216;auto update statistics&#8216; sont activées pour une base que ses tables et indexes ont toujours [...]]]></description>
			<content:encoded><![CDATA[<p>Quand on tombe sur un problème de performance de requête, il faut entre autres choses vérifier si les statistiques sur les tables ont bien été recompilées récemment. En effet, ce n&#8217;est pas parce que les options &#8216;<em>auto create statistics</em>&#8216; et &#8216;<em>auto update statistics</em>&#8216; sont activées pour une base que ses tables et indexes ont toujours des statistiques à jour.</p>
<p>On va créer une base de test pour démontrer ce point:</p>
<pre><span style="color: #000080;">create database test_statistics</span></pre>
<p>On va vérifier si les options de création et de mise à jour auto sont bien activées</p>
<pre><span style="color: #000080;">select databasepropertyex('test_statistics','IsAutoCreateStatistics')
select databasepropertyex('test_statistics','IsAutoUpdateStatistics')</span></pre>
<pre><span style="color: #008000;"><em>1
1</em></span></pre>
<p>On créé un peu de volumétrie et on ajoute les indexes clusterisés</p>
<pre><span style="color: #000080;">use test_statistics
create table STATS1(a numeric identity, b varchar(400))
create table STATS2(a numeric identity, b varchar(400))
insert into STATS1 values (replicate('a',400))
go 1000
insert into STATS2 values (replicate('a',400))
go 1000
alter table STATS1 add constraint PK_STATS1 primary key (a)
alter table STATS2 add constraint PK_STATS2 primary key (a)</span></pre>
<p>On fixe ensuite la date de dernière mise à jour des stats pour les deux tables avec STATS_DATE()</p>
<pre><span style="color: #000080;">select object_name(object_id), stats_date(object_id,stats_id) FROM sys.stats S
inner</span><span style="color: #000080;"> join sys.tables T on T.object_id = S.object_id

</span><span style="color: #008000;"><em>STATS1    2010-01-28 17:41:45.617
STATS2    2010-01-28 17:41:45.963</em>
</span></pre>
<p>A partir de là, on va forcer le calcul des stats en <strong>NORECOMPUTE </strong>sur STATS1 seulement et revérifier les dates de stats. <strong>NORECOMPUTE </strong>aura pour effet de dire à SQL Server de ne plus compiler en auto sur cette table.</p>
<pre><span style="color: #000080;">update statistics dbo.STATS1 PK_STATS1 WITH NORECOMPUTE</span>
<em><span style="color: #808080;"><span style="color: #008000;"> Command(s) completed successfully.</span>
</span></em><span style="color: #000080;">
select object_name(S.object_id), stats_date(S.object_id,S.stats_id) FROM sys.stats S
inner join sys.tables T on T.object_id = S.object_id
</span><span style="color: #808080;"><em><span style="color: #008000;">STATS1    2010-01-28</span> <span style="color: #ff0000;"><strong>17:42:14.350 </strong></span></em></span><em>
<span style="color: #008000;">STATS2    2010-01-28 17:41:45.963</span></em>
</pre>
<p>La date pour STATS1 a bien été modifiée. OK<br />
On va générer quelques perturbations identiques aux niveau des deux tables comme ajouter une colonne, supprimer des lignes, etc de manière à déclencher <strong>statman</strong>, l&#8217;utilitaire de recompilation auto des stats&#8230; On le verra passer dans une session Profiler:</p>
<p><a href="http://blog.capdata.fr/wp-content/uploads/2010/01/autostats.png"><img class="alignnone size-full wp-image-455" title="autostats" src="http://blog.capdata.fr/wp-content/uploads/2010/01/autostats.png" alt="" width="469" height="331" /></a></p>
<p>Si  on revérifie maintenant les dates de mise à jour:</p>
<pre><span style="color: #000080;">select object_name(S.object_id), stats_date(S.object_id,S.stats_id) FROM sys.stats S
inner join sys.tables T on T.object_id = S.object_id</span>
<span style="color: #808080;"><em><span style="color: #008000;">STATS1    2010-01-28 17:42:14.350
</span><span style="color: #008000;">STATS2    2010-01-28 </span><span style="color: #ff0000;"><strong>17:47:59.630</strong></span></em></span></pre>
<p>Cette fois seule STATS2 a été modifiée. Il faudra donc que je prévoie de mettre à jour manuellement STATS1 à intervalles réguliers, 1 fois par jour la nuit par exemple.</p>
<p><strong>Conclusion </strong>pour retrouver sur une base les tables qui sont passées en norecompute au niveau des stats:</p>
<pre><span style="color: #000080;">select T.name 'tablename', S.name 'statsname', S.no_recompute
from sys.tables T
INNER JOIN sys.stats S on S.object_id = T.object_id
WHERE S.no_recompute = 1</span>

<em><span style="color: #808080;"><span style="color: #008000;">tablename             statsname                        no_recompute
-------------------  -------------------------------  ------------------------------
STATS1                PK_STATS1                       1
</span>
</span></em></pre>
<p><span style="color: #000000;"><em>A+ [David B.]</em></span></p>
<p><em><span style="color: #808080;"> </span></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/mysql-et-les-tables-temporaires-internes/" rel="bookmark" title="6 janvier 2010">MySQL et les tables temporaires internes</a> (Cédric PEINTRE) [MySQL]</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/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
<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/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.654 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%2Fsql-server-retrouver-les-tables-dont-les-stats-ne-sont-plus-compilees-en-automatique%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsql-server-retrouver-les-tables-dont-les-stats-ne-sont-plus-compilees-en-automatique%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/Xbgl-2q-TQQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sql-server-retrouver-les-tables-dont-les-stats-ne-sont-plus-compilees-en-automatique/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sql-server-retrouver-les-tables-dont-les-stats-ne-sont-plus-compilees-en-automatique/</feedburner:origLink></item>
		<item>
		<title>MySQL et les tables temporaires internes</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/LGovMuOrIYw/</link>
		<comments>http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 16:04:34 +0000</pubDate>
		<dc:creator>Cédric PEINTRE</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[blob]]></category>
		<category><![CDATA[engine]]></category>
		<category><![CDATA[max_heap_table_size]]></category>
		<category><![CDATA[tables temporaires]]></category>
		<category><![CDATA[temporary tables]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[tmp_table_size]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=293</guid>
		<description><![CDATA[MySQL créé des tables temporaires automatiquement lors de certaines sélections de données, en particulier lors de l&#8217;utilisation des clauses ORDER BY ou GROUP BY.
Le détail des cas de création de tables temporaires est disponible dans la documentation MySQL :

http://dev.mysql.com/doc/refman/5.1/en/internal-temporary-tables.html

Ces tables temporaires sont créées en mémoire par défaut, dans la limite de la taille définie par [...]]]></description>
			<content:encoded><![CDATA[<p>MySQL créé des tables temporaires automatiquement lors de certaines sélections de données, en particulier lors de l&#8217;utilisation des clauses <em>ORDER BY</em> ou<em> GROUP BY</em>.</p>
<p>Le détail des cas de création de tables temporaires est disponible dans la documentation MySQL :</p>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/internal-temporary-tables.html" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/internal-temporary-tables.html</a></li>
</ul>
<p>Ces tables temporaires sont créées en mémoire par défaut, dans la limite de la taille définie par le paramètre <strong><em>tmp_table_size</em> </strong>[taille par défaut dépendante de l'OS]. Au delà de cette limite, la table temporaire est créée sur disque. Attention toutefois, si la valeur du paramètre <em>max_heap_table_size</em> [16M par défaut] est inférieure à celle de <em>tmp_table_size</em>, alors les tables temporaires en mémoire seront limitées à <em>max_heap_table_size</em>. Pour simplifier les choses, positionnez les deux paramètres à la même valeur.</p>
<p>Il est évidemment plus performant de provoquer le maximum de création en mémoire en positionnant la valeur du paramètre<em> tmp_table_size</em> à une taille relativement importante (16M à 32M).<br />
Attention toutefois au débordement mémoire, en effet, cette taille peut potentiellement être consommée par chaque thread connecté !</p>
<p>La colonne <em>Extra </em>de la commande <em>EXPLAIN </em>pour une requête de type <em>SELECT </em>permet d&#8217;obtenir une information sur la création d&#8217;une éventuelle table temporaire.<br />
Dans ce cas (utilisation d&#8217;un<em> GROUP BY</em>), une table temporaire sera créée :</p>
<p style="text-align: center;">*************************** 1. row ***************************<br />
id: 1<br />
select_type: SIMPLE<br />
table: t_evenement<br />
type: ALL<br />
possible_keys: NULL<br />
key: NULL<br />
key_len: NULL<br />
ref: NULL<br />
rows: 14988<br />
Extra: <strong>Using temporary</strong>; Using filesort</p>
<p>En revanche, cette commande ne permet pas de savoir si la table temporaire est créée sur disque ou en mémoire, pour cela, il faudra s&#8217;appuyer sur les compteurs MySQL évoqués dans la suite de l&#8217;article.</p>
<p>Le graphe suivant présente un état des tables temporaires créées en mémoire et sur disque pour notre instance de production  :</p>
<div id="attachment_378" class="wp-caption aligncenter" style="width: 549px"><a href="http://www.capdata.fr/support-DBA-oracle-sqlserver-mysql-sybase.htm"><img class="size-full wp-image-378  " src="http://blog.capdata.fr/wp-content/uploads/2010/01/temporay_tables.jpg" alt="Tables temporaires" width="539" height="376" /></a><p class="wp-caption-text">Tables temporaires MySQL</p></div>
<p>Les compteurs MySQL utilisés pour relever ces valeurs sont<code> <em>Created_tmp_table</em> et <em>Created_tmp_disk_tables</em>.</code> Il n&#8217;est malheureusement pas possible de connaitre la taille consommée en mémoire ou sur disque par ces tables temporaires.</p>
<p>Ici, la quasi totalité des tables temporaires est créée sur disque. La taille maximum d&#8217;une table temporaire en mémoire est pourtant positionnée à une valeur relativement importante (48M).</p>
<p><strong>Le fait d&#8217;augmenter la valeur du <em>tmp_table_size</em> ne changera rien dans ce cas ! Explications :</strong></p>
<p>MySQL utilise le moteur de stockage <a href="http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html" target="_blank"><em>MEMORY </em></a>pour la création des tables temporaires internes. Ce moteur se comporte quasiment comme <em>MyISAM</em>, cependant, une  contrainte  de ce moteur vient perturber le fonctionnement des tables temporaires internes : <strong>Il n&#8217;est pas possible d&#8217;utiliser des colonnes de type BLOB ou TEXT pour les tables <em>MEMORY</em>.</strong></p>
<p>De ce fait, si MySQL doit créer une table temporaire pour un ordre <em>SELECT </em>contenant ces types de colonne, elle sera automatiquement créée sur disque.</p>
<p>Deux possibilités s&#8217;offrent à vous dans ce cas :</p>
<ul>
<li>Limiter l&#8217;utilisation des colonnes de type BLOB ou TEXT</li>
<li>Monter un système de fichier mémoire pour le stockage des tables temporaires interne MySQL</li>
</ul>
<p>[ Cédric P ]<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/sql-server-retrouver-les-tables-dont-les-stats-ne-sont-plus-compilees-en-automatique/" rel="bookmark" title="28 janvier 2010">Retrouver les tables dont les stats ne sont plus compilées en automatique</a> (David BAFFALEUF) [SQL Server]</li>
<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/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/xtradb-sauvegarde-votre-cache-et-ca-marche/" rel="bookmark" title="9 mars 2010">XtraDB sauvegarde votre cache, et ça marche !</a> (Cédric PEINTRE) [MySQL]</li>
</ul>
<p><!-- Similar Posts took 3.759 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%2Fmysql-et-les-tables-temporaires-internes%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmysql-et-les-tables-temporaires-internes%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/LGovMuOrIYw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/</feedburner:origLink></item>
		<item>
		<title>Règles d’installation de base (épisode 2)</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/GZebEvQDXkY/</link>
		<comments>http://blog.capdata.fr/index.php/regles-d%e2%80%99installation-de-base-episode-2/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 09:24:15 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[installation]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=223</guid>
		<description><![CDATA[Suite de l&#8217;épisode précédent.
Une fois le matériel commandé, livré, déballé, racké, etc&#8230;, il va falloir installer Windows et SQL Server. Là encore il va falloir regarder certains détails de près :
Paramétrage de Windows Server:
Préparation des disques:
On l&#8217;a dit dans l&#8217;épisode 1, le disque c&#8217;est le nerf de la guerre. Je vais donc apporter un soin [...]]]></description>
			<content:encoded><![CDATA[<p>Suite de l&#8217;épisode <a href="http://blog.capdata.fr/?p=130">précédent</a>.</p>
<p>Une fois le matériel commandé, livré, déballé, racké, etc&#8230;, il va falloir installer Windows et SQL Server. Là encore il va falloir regarder certains détails de près :</p>
<h2>Paramétrage de Windows Server:</h2>
<h3><strong>Préparation des disques</strong>:</h3>
<p>On l&#8217;a dit dans l&#8217;épisode 1, le disque c&#8217;est le nerf de la guerre. Je vais donc apporter un soin particulier à la configuration de mes axes.</p>
<p><strong>Pour placer sur disque une base de données transactionnelle, on essaie de considérer deux règles de base:</strong></p>
<ul>
<li><strong> Toujours séparer physiquement le fichier de données du journal de transactions</strong>: pour deux raisons. La première pour la sécurité des données: si je perds mon disque de données, j&#8217;ai besoin d&#8217;avoir accès au journal pour récupérer les dernières transactions validées mais pas encore prises par le backup log. La seconde pour des raisons de performances: le critère qui pèse le plus dans le temps de service d&#8217;un disque, c&#8217;est le déplacement de la tête au dessus de la bonne piste (<em>seek time</em>). Les accès aux données sont de nature aléatoire et donc augmentent cette latence de recherche. En revanche, les accès sur le journal sont séquentiels, donc limitent le seek time car une fois la tête positionnée sur la bonne piste / bon secteur, elle glisse tranquillement pour lire (recovery) ou écrire (commit / checkpoints) sur les secteurs adjacents. Mélanger les deux, ça plombe les accès au journal, et sur une instance OLTP, on sait que l&#8217;accès en écriture sur le journal est critique car il conditionne le temps de réponse du commit.</li>
</ul>
<ul>
<li><strong>Toujours séparer </strong><strong>physiquement </strong><strong>les données des sauvegardes</strong>: pour une raison évidente de sécurité des données, mais il faut y penser avant d&#8217;avoir un problème. Et par défaut jusqu&#8217;en SQL Server 2005, tout allait dans ~MSSQL\Data et ~MSSQL\Backup.</li>
</ul>
<p><strong>Séparer physiquement</strong>, ça veut dire <strong>PAS</strong> sur les mêmes disques. Ce n&#8217;est pas parce que j&#8217;ai trois lecteurs E:\, F:\ et G:\ que j&#8217;ai trois disques, il faudra le vérifier avec la console de gestion des volumes (diskmgmt.msc) et avec votre ami l&#8217;administrateur système en charge du stockage pour vérifier s&#8217;il ne vous a pas refilé 3 LUNs découpées dans le même diskgroup. Si je reprends mon Proliant DL 580 G5  avec ses 16 slots:</p>
<p style="text-align: center;"><img class="size-full wp-image-326 aligncenter" src="http://blog.capdata.fr/wp-content/uploads/2010/01/proliant4.png" alt="proliant" width="633" height="393" /></p>
<p>Je me paye même le luxe d&#8217;avoir un RAID10 pour placer mes filegroups d&#8217;indexes, comme sur Oracle. Cela dit, la bagarre va être rude parce que tout le monde pense que l&#8217;espace disque est gâché, surtout pour ce qui concerne les journaux de transactions, où on va utiliser peut être 20% de l&#8217;espace alloué. Mais il faut le voir comme un investissement. Vous aurez des temps de service garantis de moins de 4 ms en écriture sur le commit, et le nombre de transactions par seconde va en bénéficier. C&#8217;est une réalité, on voit des exemples de ce type régulièrement chez nos clients. <em> </em></p>
<p>Une fois les axes définis et montrés à la machine, la première chose va être de partitionner le disque en alignant sur le 128ième secteur (=64K), sous diskpart:</p>
<pre><span style="color: #0000ff;">diskpart&gt; create partition primary align=64</span></pre>
<p>Globalement, il faut savoir que jusqu&#8217;en version 2003 incluse, Windows continue de préréserver les 63 premiers secteurs d&#8217;un disque pour y stocker son MBR (master boot record). Lorsque l&#8217;on va formater ensuite le file system en 64K, le premier offset va commencer réellement sur le 63ième secteur et décaler les clusters NTFS de 512 octets (1 secteur). il faut que les écritures de SQL Server (64K) soient alignées avec le début de la partition. Pour davantage d&#8217;infos, voir l&#8217;<a href="http://mikedavem.developpez.com/sqlserver/tutoriels/architecture/">article</a> de David BARBARIN sur le sujet.</p>
<p><strong>En deux étapes:</strong></p>
<ul>
<li>Partitionner le disque en alignant sur le 128ième secteur.</li>
<li>Puis créer un FS en NTFS avec un cluster size de 64K pour les disques de données et de journaux.</li>
</ul>
<p>Il faudra aussi aller vérifier que la politique d&#8217;écriture est bien en write-through au niveau du cache du contrôleur disque. Cet exemple sous OpenManage:</p>
<p style="text-align: center;"><img class="size-full wp-image-333 aligncenter" src="http://blog.capdata.fr/wp-content/uploads/2010/01/openManage_WriteThrough1.jpg" alt="openManage_WriteThrough1" width="427" height="145" /></p>
<h3><strong>Paramètres noyau de Windows pour SQL Server:</strong></h3>
<p>Pas grand chose à faire dans 99% des cas. Il faut valider que le bail (<em>quantum</em> en anglais) par thread est bien de type &#8216;long&#8217; dans les performances avancées de la machine (<em>Poste de Travail -&gt; Properties -&gt; Advanced -&gt; Performance -&gt; Advanced</em>):</p>
<p style="text-align: center;"><img class="size-full wp-image-295 aligncenter" src="http://blog.capdata.fr/wp-content/uploads/2010/01/processsched.png" alt="processsched" width="331" height="111" /></p>
<p>Background services =&gt; chaque thread a le droit de s&#8217;exécuter pendant 12 ticks d&#8217;horloge avant d&#8217;être interrompu par le Dispatcher.  Par défaut sur la gamme Server, le radiobutton doit être sur background services (quantum = 12 ticks d&#8217;horloge) et sur la gamme workstation, sur Programs (quantum = 2 ticks d&#8217;horloge). En général pour tous les SGBD, le quantum doit être plus long pour limiter le nombre de changements de contexte opérés par le système d&#8217;exploitation. Pour plus de détails, voir cet <a href="http://blog.capdata.fr/?p=159">article</a>.</p>
<p>Il faudra aussi aller vérifier que les ressources allouées seront en priorité sur les programmes générant beaucoup d&#8217;IOs comme SQL Server (<em>Connexions réseau, clic-droit sur l&#8217;interface réseau -&gt; Properties-&gt; File and Printer Sharing (et oui !) -&gt; Properties</em>):</p>
<p style="text-align: center;"><img class="size-full wp-image-298 aligncenter" src="http://blog.capdata.fr/wp-content/uploads/2010/01/maximizethroughput.jpg" alt="maximizethroughput" width="381" height="191" /></p>
<p>Maximize throughput for network applications: sous entendu on n&#8217;est pas là pour faire du partage de fichiers.</p>
<p>Et éviter l&#8217;utilisation des antivirus autant que possible.</p>
<h3>Compte de service pour SQL Server et l&#8217;agent:<em> </em></h3>
<p>Le compte de service est le compte déclaré au niveau de la machine ou du domaine pour supporter l&#8217;exécution de SQL Server et l&#8217;ensemble de ses interactions avec le système: poster des IOs, atteindre des machines sur le réseau, écrire dans un fichier de sauvegarde, etc&#8230; Toutes ces actions seront donc exécutées sous le contexte de droits du compte de service.  Dans la plupart des cas, les SQL  Server sont démarrés sous le contrôle des comptes systèmes locaux (LOCAL SYSTEM) avec lesquels sont lancés la plupart des modules de windows exécutés en mode user (smss.exe, crss.exe, lsass.exe, winlogon.exe, etc&#8230;). Et négligence du  DBA, on trouve aussi des SQL Server démarrés sous le compte Administrateur local voire de domaine, ce qui du point de vue sécurité  n&#8217;est pas vraiment l&#8217;idéal.</p>
<p>Et bien depuis la version SQL Server 2005, il n&#8217;y a plus d&#8217;excuse: on créé simplement des comptes utilisateurs locaux ou de domaine sans privilège *** pour SQL Server et SQL Agent (je ne parle pas de SQL Browser puisque du point de vue sécurité, on ne doit pas l&#8217;utiliser **), on les passe ensuite à l&#8217;assistant d&#8217;installation qui créé des groupes avec les droits appropriés, et y intègre les comptes qui héritent du coup des droits strictement nécessaires.</p>
<h2>Éléments à définir avant l&#8217;installation de SQL Server :</h2>
<p>Avant de lancer le setup,il faut réfléchir à quelques éléments caractéristiques de l&#8217;instance que l&#8217;on souhaite installer:</p>
<h3>Instance locale / instance nommée:</h3>
<p>L&#8217;instance locale est l&#8217;instance que l&#8217;on créé par défaut sur une machine. Elle prend par défaut le nom de la machine et le port 1433 attribué par l&#8217;IANA. On ne peut donc en créer qu&#8217;une seule par machine. Ma chaîne de connexion ressemblera à :</p>
<pre><span style="color: #0000ff;">sqlcmd -Udba_exploit -w1000 -S PIXIES </span></pre>
<p>Où PIXIES est le nom de ma machine, et donc le nom de mon instance locale par la même occasion. Maintenant, lorsqu&#8217;on souhaite en installer plus d&#8217;une par machine, on pourra utiliser les instances nommées, dont le nom sera constitué d&#8217;un préfixe (nom de la machine hôte) et d&#8217;un suffixe (nom de l&#8217;instance à choisir) séparés par un backslash (&#8216;\&#8217;). Dans ce cas, ma chaîne de connexion ressemblera à :</p>
<pre><span style="color: #0000ff;">sqlcmd -Udba_exploit -w1000 -S PIXIES\SQL1 </span></pre>
<p>Où SQL1 sera le nom de nom instance nommée. Autre différence majeure, le port de démarrage sera défini dynamiquement. Ce qui signifie qu&#8217;il peut changer entre deux redémarrages, donc problème de firewall à l&#8217;horizon. Pour l&#8217;éviter, il faudra fixer le port de démarrage de l&#8217;instance dans les propriétés TCP, et redémarrer SQL Server. **</p>
<h3>Collation:</h3>
<p>La collation va définir la manière de coder les caractères dans ma base de données. Là aussi le sujet est vaste et largement débattu sur le net. Il faut simplement réfléchir aux types de champs texte que mon application va devoir stocker et choisir le codepage approprié. Il faut essayer de prendre le codepage le plus large possible. Lors de l&#8217;installation en SQL Server 2005, deux types de collations sont proposées: les collations windows et les collations SQL Server. En fait la seconde est incluse pour compatibilité vers les versions précédentes, et ne doit donc être utilisée que pour assurer la compatibilité lors d&#8217;une migration. Il vaut mieux essayer de partir avec une collation Windows dès le départ, elles sont plus riches et plus précises, notamment lorsqu&#8217;on utilise à la fois des colonnes UNICODE et NON-UNICODE, car la collation windows sait convertir du NON-UNICODE à la volée.  Changer la collation à tous niveaux n&#8217;est pas une opération de routine: au niveau de l&#8217;instance, il faudra la reconstruire, au niveau de la base c&#8217;est plus <a title="Changer la collation d'une base" href="http://blog.capdata.fr/?p=222">épique encore.<br />
</a></p>
<h3>Mode d&#8217;authentification:</h3>
<p>Deux solutions:</p>
<ul>
<li><em><strong>Le mode intégré</strong></em>: l&#8217;authentification se fait par une autorité telle qu&#8217;un contrôleur de domaine ou la machine locale. Avantage, SQL Server ne stocke pas de mot de passe, côté sécurité c&#8217;est la meilleure option. Inconvénient, lorsqu&#8217;on souhaite atteindre depuis son application cliente une instance qui n&#8217;est pas dans le même domaine, ou simplement une machine en workgroup, l&#8217;authentification intégrée ne fonctionnera pas.</li>
<li><em><strong>Le mode mixte:</strong></em> donc on sera obligé de permettre aussi de créer et d&#8217;utiliser  des comptes et des mots de passe dans SQL Server. En mode mixte, on se connecte soit avec un compte windows, soit avec un compte SQL Server.</li>
</ul>
<p>Les bonnes pratiques de sécurité préconisent de rester en mode intégré, mais ce n&#8217;est n&#8217;est bien souvent pas très pratique, et donc pas appliqué. Il vaut mieux autoriser le mode mixte mais désactiver le compte sa, et faire appliquer la politique de mots de passe de Windows.</p>
<p>Une fois ces étapes validées, l&#8217;installation peut commencer. Le travail de préparation est terminé.</p>
<p>A bientôt !</p>
<p><em><strong>* </strong>Dans cet exemple, on choisit de faire les backups sur un partage CIFS</em><br />
<em><strong>** </strong>Je ne parle pas de sécurité dans cet article, le sujet est vaste et fera l&#8217;objet d&#8217;un prochain post.<br />
<strong>*** </strong>Penser à cocher le compte n&#8217;expire jamais pour les comptes de service. </em></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/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/" rel="bookmark" title="11 décembre 2008">Modes de récupération et journal de transactions, épisode 2</a> (David BAFFALEUF) [SQL Server]</li>
<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/sql-server-regles-dinstallation-de-base-episode-1/" rel="bookmark" title="18 juin 2009">Règles d&#8217;installation de base (épisode 1)</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.118 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%2Fregles-d%25e2%2580%2599installation-de-base-episode-2%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fregles-d%25e2%2580%2599installation-de-base-episode-2%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/GZebEvQDXkY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/regles-d%e2%80%99installation-de-base-episode-2/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/regles-d%e2%80%99installation-de-base-episode-2/</feedburner:origLink></item>
		<item>
		<title>Oracle, les Rpms plus de souci avec YUM</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/XJpIsDOP4bQ/</link>
		<comments>http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 15:58:02 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[public-yum]]></category>
		<category><![CDATA[redhat]]></category>
		<category><![CDATA[rpm]]></category>
		<category><![CDATA[yum]]></category>

		<guid isPermaLink="false">http://blog.capdata.fr/?p=288</guid>
		<description><![CDATA[Un truc sympa, vous en avez marre d&#8217;installer des rpms avec Oracle ou des soucis de dépendance ..
La solution http://public-yum.oracle.com  et YUM.
[root@OEL5-ORA1 yum.repos.d]# cd /etc/yum.repos.d
[root@OEL5-ORA1 yum.repos.d]#wget http://public-yum.oracle.com/public-yum-el5.repo
car j&#8217;utilise OEL 5 Update 4
[root@OEL5-ORA1 ~]# cat /etc/enterprise-release
Enterprise Linux Enterprise Linux Server release 5.4 (Carthage)
Je vais modifier le fichier public-yum-el5.repo en mettant enabled=1 pour ma version el5_u4_base
vi [...]]]></description>
			<content:encoded><![CDATA[<p>Un truc sympa, vous en avez marre d&#8217;installer des rpms avec Oracle ou des soucis de dépendance ..</p>
<p>La solution <a href="http://public-yum.oracle.com/">http://public-yum.oracle.com </a> et YUM.</p>
<p><em>[root@OEL5-ORA1 yum.repos.d]#</em><em> cd /etc/yum.repos.d<br />
[root@OEL5-ORA1 yum.repos.d]#</em><em>wget http://public-yum.oracle.com/public-yum-el5.repo</em></p>
<p>car j&#8217;utilise OEL 5 Update 4</p>
<p>[root@OEL5-ORA1 ~]# cat /etc/enterprise-release<em><br />
Enterprise Linux Enterprise Linux Server release 5.4 (Carthage)</em></p>
<p>Je vais modifier le fichier public-yum-el5.repo en mettant enabled=1 pour ma version <em>el5_u4_base</em></p>
<p>vi public-yum-el5.repo</p>
<p><em>&#8230;<br />
</em></p>
<p><em>[el5_u4_base]<br />
name=Enterprise Linux $releasever U4 &#8211; $basearch &#8211; base<br />
baseurl=http://public-yum.oracle.com/repo/EnterpriseLinux/EL5/4/base/$basearch/<br />
gpgkey=http://public-yum.oracle.com/RPM-GPG-KEY-oracle-el5<br />
gpgcheck=1<br />
<strong>enabled=1</strong></em></p>
<p><em>&#8230;</em></p>
<p>[root@OEL5-ORA1 yum.repos.d]# yum list oracleasm<br />
<em>Loaded plugins: security<br />
Error: No matching Packages to list<br />
ocfs2 packages are not available. Let’s install it now</em></p>
<p>[root@OEL5-ORA1 yum.repos.d]# yum install oracleasm</p>
<p><em>Loaded plugins: security<br />
Setting up Install Process<br />
Package oracleasm-2.6.18-164.el5-2.0.5-1.el5.i686 already installed and latest version<br />
Nothing to do</em></p>
<p>Quel plaisir <img src='http://blog.capdata.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> <em><br />
</em><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
<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/sybase-ase-direct-io-dsync-onoff-raw-device/" rel="bookmark" title="18 juin 2009">Direct i/o, dsync on/off, raw device</a> (David BAFFALEUF) [Sybase]</li>
</ul>
<p><!-- Similar Posts took 3.884 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%2Foracle-les-rpms-et-les-dependances-avec-yum%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Foracle-les-rpms-et-les-dependances-avec-yum%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/XJpIsDOP4bQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/</feedburner:origLink></item>
		<item>
		<title>Modifier la Collation d’une base SQL 2005</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/H4ao6H4Uo3o/</link>
		<comments>http://blog.capdata.fr/index.php/modifier-la-collation-dune-base-sql-2005/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 13:05:48 +0000</pubDate>
		<dc:creator>Louis HOCHBERG</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[sql server collation]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=222</guid>
		<description><![CDATA[L’objectif de cet article est de présenter une méthode pour changer la collation d’une base de données.]]></description>
			<content:encoded><![CDATA[<p><!--[if gte mso 9]&gt;  Normal 0 21         MicrosoftInternetExplorer4  &lt;![endif]--><!--  /* Font Definitions */  @font-face 	{font-family:SimSun; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:宋体; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;} @font-face 	{font-family:Verdana; 	panose-1:2 11 6 4 3 5 4 4 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1593833729 1073750107 16 0 415 0;} @font-face 	{font-family:"\@SimSun"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-update:auto; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:Verdana; 	mso-fareast-font-family:SimSun; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-font-weight:bold;} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 70.85pt 70.85pt 70.85pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --><!--[if gte mso 10]&gt; &lt;!   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tableau Normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} --> <!--[endif]--></p>
<p class="MsoNormal">La collation (ou classement en français) d’une base de données indique le jeu de caractères et l’ordre de tri des données stockées dans la base de données. De nombreux articles expliquent le rôle et traitent des problèmes de collation. L’objectif de celui-ci est de présenter une méthode pour changer la collation d’une base de données.</p>
<p>La collation peut être fixée:</p>
<ol>
<li>Au niveau de l’instance: à l’installation de SQL Server 2005.</li>
<li>Au niveau de la base:
<pre> CREATE DATABASE ... COLLATE ou ALTER DATABASE ... COLLATE.</pre>
</li>
<li>Au niveau de la colonne:
<pre>CREATE TABLE maTable ... COL1 NVARCHAR(100) COLLATE French_CI_AS</pre>
</li>
<li>Au niveau de l’expression SQL:
<pre>SELECT A, B from T1, T2 where T1.A = T2.B collate French_CI_AS</pre>
</li>
</ol>
<p class="MsoNormal">On peut parfois se retrouver dans la situation suivante :  la base de données a été créée ou restaurée dans une collation qui pose problème à l’application et il faut la modifier.</p>
<p class="MsoNormal"><!--[if gte mso 9]&gt;  Normal 0 21         MicrosoftInternetExplorer4  &lt;![endif]--><!--  /* Font Definitions */  @font-face 	{font-family:SimSun; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:宋体; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;} @font-face 	{font-family:Verdana; 	panose-1:2 11 6 4 3 5 4 4 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1593833729 1073750107 16 0 415 0;} @font-face 	{font-family:"\@SimSun"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-update:auto; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:Verdana; 	mso-fareast-font-family:SimSun; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-font-weight:bold;} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 70.85pt 70.85pt 70.85pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --><!--[if gte mso 10]&gt; &lt;!   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tableau Normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} --> <!--[endif]--></p>
<p class="MsoNormal"><strong>Attention</strong>, gare alors aux problèmes lorsque l’on utilise des bases de collations différentes sur une même instance : La collation de tempdb est héritée de model, qui elle-même hérite de celle de l’instance. Lors de jointures avec des tables temporaires sur des colonnes contenant du texte, des erreurs de comparaison peuvent survenir:<span> </span></p>
<pre><span lang="EN-GB">Msg 468, Level 16, State 9, Line 5 Cannot resolve the collation conflict between
"French_CI_AS" and "Latin1_General_CI_AS_KS_WS" in the equal to operation</span></pre>
<p class="MsoNormal"><!--[if gte mso 9]&gt;  Normal 0 21         MicrosoftInternetExplorer4  &lt;![endif]--><!--  /* Font Definitions */  @font-face 	{font-family:SimSun; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:宋体; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;} @font-face 	{font-family:Verdana; 	panose-1:2 11 6 4 3 5 4 4 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1593833729 1073750107 16 0 415 0;} @font-face 	{font-family:"\@SimSun"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-update:auto; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:Verdana; 	mso-fareast-font-family:SimSun; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-font-weight:bold;} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 70.85pt 70.85pt 70.85pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --><!--[if gte mso 10]&gt; &lt;!   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tableau Normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} --> <!--[endif]--></p>
<p class="MsoNormal">Pour changer la collation d’une base de données, il existe plusieurs techniques :</p>
<p class="MsoNormal"><strong><span style="#ff9900;">Technique 1 : </span></strong></p>
<ol>
<li>Modifier la collation de la base : <span style="&quot;Courier New&quot;;">ALTER DATABASE &#8230; COLLATE<br />
</span>Toutes les nouvelles colonnes de type caractère créées dans la base hériteront de la nouvelle collation mais pas les colonnes caractère déjà créées .</li>
<li>Modifier <span> </span>la collation de chaque colonne à condition quelle ne soit pas référencée dans un index, une contrainte Foreign key ou CHECK, une statistique de distribution ou une colonne calculée<br />
… pas évident</li>
</ol>
<p class="MsoNormal"><span style="#ff9900;"><strong>Technique 2</strong> </span>: celle que je vous propose</p>
<ol>
<li>Générer le script de création de la base et de tous ses objets</li>
<li>Modifier ce script, pour créer une nouvelle base vide avec la bonne collation</li>
<li>Importer dans la nouvelle base les données de l’ancienne base à l’aide de l’assistant de Management Studio</li>
<li>Vérifier si l’application fonctionne correctement sur la nouvelle base</li>
<li>Intervertir l’ancienne base et la nouvelle<br />
On peut renommer une base ( commande <span style="&quot;Courier New&quot;;">ALTER DATABASE … MODIFY NAME</span>). Attention de bien récupérer les comptes utilisateurs de l’ancienne base et le mapping sur les logins.</li>
</ol>
<p class="MsoNormal"><strong>Exemple </strong>: Changer la collation de la base AdventureWorks Latin1_General_CS_AS en<span> </span>En French_CI_AS</p>
<p>Avant de commencer:</p>
<p style="30px;">&#8211; Vérifier la collation du serveur</p>
<pre style="30px;">sp_helpsort</pre>
<pre style="30px;"><span style="#ff9900;"><span style="#3366ff;">Server default collation
---------------------------------------------------------------------------
French, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive</span></span></pre>
<p style="30px;">&#8211; Vérifier la collation de la base</p>
<pre style="30px;"><span style="#3366ff;"><span style="#000000;">select DATABASEPROPERTYEX('AdventureWorks', 'Collation')</span>
-----------------------------------------------------------------------
Latin1_General_CS_AS</span></pre>
<p style="30px;">&#8211; Vérifier la collation des colonnes</p>
<pre style="30px;">SELECT B.table_name, column_name, collation_name, data_type FROM INFORMATION_SCHEMA.COLUMNS A,
INFORMATION_SCHEMA.TABLES B
WHERE A.table_name = B.table_name and collation_name is not null
ORDER BY B.table_name</pre>
<pre style="30px;"><span style="#3366ff;">table_name    column_name   collation_name             data_type
-----------------------------------------------------------------------------------
Address       AddressLine1  Latin1_General_CS_AS        nvarchar
Address       AddressLine2  Latin1_General_CS_AS        nvarchar
...</span></pre>
<blockquote>
<p class="MsoNormal"><span lang="EN-GB"><span> </span></span></p>
</blockquote>
<p class="MsoNormal"><span style="#ff9900;"><strong>Etape 1</strong></span> : Générer le script de création de la base et de tous ses objets</p>
<p class="MsoNormal">A Partir de Management Studio, cliquer sur &#8220;Generate Scripts&#8221;</p>
<p class="MsoNormal"><a href="https://www.alldb.fr/blog/wp-content/uploads/2009/09/genscript1.png"><img class="alignnone size-full wp-image-241" src="https://www.alldb.fr/blog/wp-content/uploads/2009/09/genscript1.png" alt="" /></a></p>
<p class="MsoNormal">&#8212;<br />
Choisir la base AdventureWorks,<br />
Cocher l&#8217;option &#8220;Script All Objects&#8221;<br />
Next<br />
&#8212;<br />
<!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]--><!--  /* Font Definitions */  @font-face 	{font-family:SimSun; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:宋体; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;} @font-face 	{font-family:Verdana; 	panose-1:2 11 6 4 3 5 4 4 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1593833729 1073750107 16 0 415 0;} @font-face 	{font-family:"\@SimSun"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-update:auto; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:Verdana; 	mso-fareast-font-family:SimSun; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-font-weight:bold;} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 70.85pt 70.85pt 70.85pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --><!--[if gte mso 10]&gt; &lt;!   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tableau Normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} --> <!--[endif]-->Choose script Options<br />
Modifier les options suivantes :<span lang="EN-GB"><br />
Include Descriptive Headers: True<br />
Script Database Create: True<br />
Script Object-Level Permissions : True<br />
Script USE DATABASE : False<br />
Script Full-Text Indexes : True</span><br />
&#8212;<br />
Next<br />
Script to New Query Window<br />
&#8212;<br />
Next<br />
&#8212;<br />
Finish<br />
&#8212;<br />
Close
</p>
<p class="MsoNormal"><span style="#ff9900;"><strong>Etape 2</strong></span> : <!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]--><!--  /* Font Definitions */  @font-face 	{font-family:SimSun; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:宋体; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;} @font-face 	{font-family:Verdana; 	panose-1:2 11 6 4 3 5 4 4 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1593833729 1073750107 16 0 415 0;} @font-face 	{font-family:"\@SimSun"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-update:auto; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:Verdana; 	mso-fareast-font-family:SimSun; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-font-weight:bold;} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 70.85pt 70.85pt 70.85pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --><!--[if gte mso 10]&gt; &lt;!   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tableau Normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} --> <!--[endif]--><span style="Verdana;">Modifier ce script, pour créer une nouvelle base vide avec la bonne collatio</span></p>
<p class="MsoNormal">Avec l&#8217;outil Find/Replace Remplacer le mot AdventureWorks par AdventureWorks_2<br />
(nom de la nouvelle base)</p>
<p><!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]--><!--  /* Font Definitions */  @font-face 	{font-family:SimSun; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:宋体; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;} @font-face 	{font-family:Verdana; 	panose-1:2 11 6 4 3 5 4 4 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1593833729 1073750107 16 0 415 0;} @font-face 	{font-family:"\@SimSun"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 680460288 22 0 262145 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-update:auto; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:Verdana; 	mso-fareast-font-family:SimSun; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-font-weight:bold;} @page Section1 	{size:612.0pt 792.0pt; 	margin:70.85pt 70.85pt 70.85pt 70.85pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} --><!--[if gte mso 10]&gt; &lt;!   /* Style Definitions */  table.MsoNormalTable 	{mso-style-name:"Tableau Normal"; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.0pt; 	font-family:"Times New Roman";} --> <!--[endif]-->
</p>
<p class="MsoNormal">Modifier la Collation de la base de données avec la valeur voulue en ajoutant la clause collate</p>
<pre><span>CREATE DATABASE
…
( NAME =
N'AdventureWorks_2_Log', FILENAME = N'C:\Program Files\Microsoft SQL
Server\MSSQL.1\MSSQL\DATA\AdventureWorks_2_Log.ldf' , SIZE = 916352KB , MAXSIZE
= UNLIMITED, FILEGROWTH = 10%)
<strong>COLLATE FRENCH_CI_AS</strong>
END</span></pre>
<p class="MsoNormal">Modifier les chemins des fichiers de données en cas de besoin (pour ne pas utiliser les mêmes que la base d’origine).</p>
<p><!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]--></p>
<p class="MsoNormal">=&gt; Exécuter le script</p>
<p class="MsoNormal">Vérifier qu’il n’y a pas d’erreur problématique lors de la création de la base et de ses objetts.<br />
Vérifier la collation de la nouvelle base et de ses colonnes.
</p>
<p class="MsoNormal"><!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]--></p>
<p class="MsoNormal">
<p class="MsoNormal"><strong>Etape 3</strong> : Importer dans la nouvelle base les données les données de l’ancienne</p>
<p class="MsoNormal">A l’aide SSMS depuis la base <span>AdventureWorks_2, lancer l’assistant d’import de données : </span></p>
<p class="MsoNormal"><!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]--></p>
<p><a href="https://www.alldb.fr/blog/wp-content/uploads/2009/09/import1.png"><img class="size-full wp-image-238 alignnone" src="https://www.alldb.fr/blog/wp-content/uploads/2009/09/import1.png" alt="Import des données avec SSMS" /></a></p>
<p class="MsoNormal">&#8212;<br />
Choose a Datasource: AdventureWorks<br />
Next<br />
&#8212;<br />
Choose a destination : AdventureWorks_2<br />
Next<br />
&#8212;<br />
Copy data from one or more tables or views<br />
Next<br />
&#8212;<br />
Ne sélectionner que les tables , pas les vues<br />
Next<br />
&#8212;<br />
Execute immediately<br />
Next<br />
Finish<br />
&#8212;-</p>
<p><!--[if gte mso 9]&gt;  Normal 0    21         MicrosoftInternetExplorer4  &lt;![endif]-->
</p>
<p class="MsoNormal">Les lignes de chaque table ont été ajoutées aux tables vides avec la nouvelle collation pour les données type Caractère</p>
<p class="MsoNormal">L.Hochberg</p>
<p><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/modifier-page_verify-apres-une-migration-depuis-sql-2000/" rel="bookmark" title="6 avril 2010">Modifier PAGE_VERIFY après une migration depuis SQL 2000</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/sql-server-principes-dune-sauvegarde-a-chaud/" rel="bookmark" title="12 décembre 2008">Principes d&#8217;une sauvegarde à chaud</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/" rel="bookmark" title="30 mars 2010">Un trigger fait-il parti d&#8217;une transaction ?</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</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>
</ul>
<p><!-- Similar Posts took 4.605 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%2Fmodifier-la-collation-dune-base-sql-2005%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fmodifier-la-collation-dune-base-sql-2005%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/H4ao6H4Uo3o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/modifier-la-collation-dune-base-sql-2005/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/modifier-la-collation-dune-base-sql-2005/</feedburner:origLink></item>
		<item>
		<title>Retrouver une transaction en échec</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/y5JMC7ZBMw0/</link>
		<comments>http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 09:05:00 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[replication]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=203</guid>
		<description><![CDATA[Aujourd&#8217;hui la réplication transactionnelle est en panne. Un coup d&#8217;oeil rapide au moniteur de réplication nous confirme que l&#8217;agent de distribution est en échec:
Command attempted:
if @@trancount &#62; 0 rollback tran
(Transaction sequence number: 0x0000CD53000011DE001000000000, Command ID: 1)

Error messages:
Syntax error, permission violation, or other nonspecific error (Source: MSSQLServer,
Error number: 20025)
Get help: http://help/20025
Syntax error, permission violation, or other [...]]]></description>
			<content:encoded><![CDATA[<p>Aujourd&#8217;hui la réplication transactionnelle est en panne. Un coup d&#8217;oeil rapide au moniteur de réplication nous confirme que l&#8217;agent de distribution est en échec:</p>
<pre><em>Command attempted:
if @@trancount &gt; 0 rollback tran
(Transaction sequence number: 0x0000CD53000011DE001000000000, Command ID: 1)

Error messages:
Syntax error, permission violation, or other nonspecific error (Source: MSSQLServer,
Error number: 20025)
Get help: http://help/20025
Syntax error, permission violation, or other nonspecific error (Source: MSSQLServer,
Error number: 42000)
Get help: http://help/42000</em></pre>
<p>Ce n&#8217;est même pas la peine d&#8217;essayer de voir ce qu&#8217;il y a au bout des deux liens <em>http://help/&#8230;</em> proposés. En gros l&#8217;agent de distribution a trouvé une erreur en essayant d&#8217;appliquer une transaction. Le but est de retrouver le code SQL qui correspond à la transaction en échec. Lancer une trace Profiler sur le distributeur ne servira pas à grand chose car la transaction en question sera noyée dans le flot de mises à jour sur les tables systèmes de la réplication. En fait la chose la plus importante dans le log d&#8217;erreur est le numéro de transaction: <strong><em></em><em>0&#215;0000CD53000011DE001000000000</em></strong></p>
<p>Pour retrouver l&#8217;ordre correspondant sur le distributeur, utiliser <strong>sp_browsereplcmds</strong>, regarder la première ligne:</p>
<pre>use distribution
sp_browsereplcmds @xact_seqno_start = '0x0000CD53000011DE001000000000'

0x0000CD53000012EE000E	NULL	NULL	1	30	0	0	NULL	NULL
0x00000000000000000000
{CALL sp_MSins_EMAIL MOBILE DATA ('MICHAEL.HEARSLEY#TATOINE.COM', 'J74K6L')}	1

0x0000CD5300001304000F	NULL	NULL	1	30	0	0	NULL	NULL
0x00000000000000000000
{CALL sp_MSins_EMAIL MOBILE DATA ('EDUARDO.ALFONSO#JPMM.COM', 'J91RCX')}	1

0x0000CD530000131A0018	NULL	NULL	1	30	0	0	NULL	NULL
0x00000000000000000000
{CALL sp_MSins_EMAIL MOBILE DATA ('MARK.D.SPELLMAN#ATTACH.CO.UK', 'J731FZ')} 1

0x0000CD530000133B000E	NULL	NULL	1	30	0	0	NULL	NULL
0x00000000000000000000
{CALL sp_MSins_EMAIL MOBILE DATA ('XAVIER.BARTOLDI#NRJ.PICATRIX.COM', 'J92HBF')} 1

...</pre>
<p>Effectivement si on lance l&#8217;exécution de la proc à la main sur le subscriber:</p>
<pre>CALL sp_MSins_EMAIL MOBILE DATA ('MICHAEL.HEARSLEY#TATOINE.COM', 'J74K6L')

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'MOBILE'.</pre>
<p>Il y a des espaces dans le nom de la proc. L&#8217;assistant graphique de mise en place de la réplication créera la procédure avec des underscores, donc pas de souci, c&#8217;est juste pour l&#8217;exemple.</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/replication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters/" rel="bookmark" title="18 juin 2009">Attention : publication transactionnelle et indexes non clusters</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</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>
<li><a href="http://blog.capdata.fr/index.php/reunion-guss-le-1er-juillet/" rel="bookmark" title="23 juin 2010">Réunion GUSS le 1er juillet !</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 4.228 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%2Freplication-sql-server-retrouver-la-vilaine-transaction-en-echec%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Freplication-sql-server-retrouver-la-vilaine-transaction-en-echec%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/y5JMC7ZBMw0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/</feedburner:origLink></item>
		<item>
		<title>Sessions consommatrices dans tempdb</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/5blcM1oSZzA/</link>
		<comments>http://blog.capdata.fr/index.php/sql-server-sessions-consommatrices-dans-tempdb/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 08:56:42 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[dbcc inputbuffer]]></category>
		<category><![CDATA[DBCCINPUTBUFFER]]></category>
		<category><![CDATA[DBCCSHOWFILESTATS]]></category>
		<category><![CDATA[monitorTempdb]]></category>
		<category><![CDATA[sessions]]></category>
		<category><![CDATA[tempdb]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=184</guid>
		<description><![CDATA[Je sais ce que vous allez dire: on l&#8217;a déjà vu partout, il y a déjà un million d&#8217;articles sur le sujet, quel intérêt pour une société qui se défend justement de poster sur des sujets originaux, etc&#8230;
Je vous répondrai que le problème n&#8217;est pas trivial. Tout le monde utilise les vues DMV pour récupérer [...]]]></description>
			<content:encoded><![CDATA[<p>Je sais ce que vous allez dire: on l&#8217;a déjà vu partout, il y a déjà un million d&#8217;articles sur le sujet, quel intérêt pour une société qui se défend justement de poster sur des sujets originaux, etc&#8230;</p>
<p>Je vous répondrai que le problème n&#8217;est pas trivial. Tout le monde utilise les vues DMV pour récupérer les infos de la session qui occupe l&#8217;espace dans tempdb, notamment le texte SQL de la requête:<br />
- <em>sys.dm_db_task_space_usage</em>: pour voir l&#8217;espace utilisé par session.<br />
- <em>sys.dm_exec_requests</em> ou <em>sys.dm_exec_query_stats</em> + <em>cross apply sys.dm_exec_sql_text(sql_handle)</em>: pour plus d&#8217;infos sur les sessions (stats + texte des requêtes).</p>
<p>Seulement voilà: les sessions dont le plan a été purgé du cache ne sont plus visibles dans les DMV sys.dm_exec&#8230; donc la jointure entre sys.dm_db_task_space_usage et sys.dm_exec&#8230; ne renverra pas d&#8217;infos pour des sessions qui utilisent pourtant bel et bien de l&#8217;espace dans tempdb.</p>
<p>Donc il faut avoir recours au bon vieux  <strong><em>dbcc inputbuffer</em></strong> pour récupérer tout ça.</p>
<p>1) D&#8217;abord, on va créer les tables de recueil.</p>
<p>1.1 DBCCINPUTBUFFER va nous permettre de récupérer le contenu du dbcc inputbuffer par session:</p>
<pre>CREATE TABLE tempdb.guest.DBCCINPUTBUFFER
(
EventType varchar(50),
Parameters int,
SQLText varchar(2000)
)</pre>
<p>1.2 DBCCSHOWFILESTATS va nous permettre de récupérer l&#8217;espace total et utilisé dans tempdb:</p>
<pre>CREATE TABLE tempdb.guest.DBCCSHOWFILESTATS
(
[fileid] [int], [filegroup] [int],
[totalextents] [int], [usedextents] [int],
[name] [varchar] (255), [filename] [varchar] (255)
)</pre>
<p>1.3 monitorTempdb sera notre table finale d&#8217;historique.</p>
<pre>CREATE TABLE tempdb.guest.monitorTempdb
(
curdate datetime,
spaceintempdb bigint,
spaceusedintempdb bigint,
spid int,
sqltext varchar(1000),
internal_objects_alloc_MB bigint,
internal_objects_dealloc_MB bigint,
user_objects_alloc_MB bigint,
user_objects_dealloc_MB bigint,
program_name varchar(100),
login_time datetime,
hostname varchar(20),
login_name varchar(100)
)</pre>
<p>2) Par session récupérer les infos et le texte de la requête: on va placer les sessions consommatrices ainsi que les espaces consommés dans un curseur, puis boucler pour chaque session_id et récupérer plus d&#8217;infos (program_name, login, etc&#8230; depuis sys.dm_exec_sessions, la seule DMV qui affiche toutes les sessions actives ou non) et le dernier texte SQL généré:</p>
<pre>use tempdb
go
declare
	@spid int,
	@sqltext varchar(1000),
	@internal_objects_alloc_page_count bigint,
	@internal_objects_dealloc_page_count bigint,
	@user_objects_alloc_page_count bigint,
	@user_objects_dealloc_page_count bigint,
	@program_name varchar(100),
	@login_time datetime,
	@hostname varchar(20),
	@login_name varchar(100),
	@SQLQUERY varchar(100),
	@spaceintempdb bigint,
	@spaceusedintempdb  bigint

declare cr_sqltext CURSOR READ_ONLY for
select session_id,internal_objects_alloc_page_count,internal_objects_dealloc_page_count,
user_objects_alloc_page_count, user_objects_dealloc_page_count
from sys.dm_db_task_space_usage where internal_objects_alloc_page_count &gt; 12000 

open cr_sqltext
fetch next from cr_sqltext into
	@spid,
	@internal_objects_alloc_page_count,
	@internal_objects_dealloc_page_count,
	@user_objects_alloc_page_count,
	@user_objects_dealloc_page_count

while @@fetch_status = 0
begin
	select
		@program_name = program_name,
		@login_time = login_time,
		@hostname = host_name,
		@login_name = login_name
	from sys.dm_exec_sessions where session_id = @spid

	select @SQLQUERY = 'dbcc inputbuffer('+convert(char(3),@spid)+')'

	insert into tempdb.guest.DBCCINPUTBUFFER exec (@SQLQUERY)
	select @sqltext = SQLText from tempdb.guest.DBCCINPUTBUFFER 

	insert into tempdb.guest.DBCCSHOWFILESTATS exec ('DBCC showfilestats with NO_INFOMSGS')
	select
		@spaceintempdb = sum(totalextents)/16,
		@spaceusedintempdb = sum(usedextents)/16
	from tempdb.guest.DBCCSHOWFILESTATS

	delete from tempdb.guest.DBCCINPUTBUFFER
	delete from tempdb.guest.DBCCSHOWFILESTATS

	insert tempdb.guest.monitorTempdb values
	(getdate(),
	@spaceintempdb,
	@spaceusedintempdb ,
	@spid, 	@sqltext,
	@internal_objects_alloc_page_count*8192/1048576 ,
	@internal_objects_dealloc_page_count*8192/1048576 ,
	@user_objects_alloc_page_count*8192/1048576 ,
	@user_objects_dealloc_page_count*8192/1048576 ,
	@program_name ,
	@login_time ,
	@hostname ,
	@login_name)

fetch next from cr_sqltext into
	@spid,
	@internal_objects_alloc_page_count,
	@internal_objects_dealloc_page_count,
	@user_objects_alloc_page_count,
	@user_objects_dealloc_page_count

end
close cr_sqltext
deallocate cr_sqltext
go</pre>
<p>Cette dernière partie peut être mise dans un job planifié toutes les minutes par exemple. C&#8217;est ainsi que j&#8217;ai découvert que sp_MSget_repl_commands et sp_MSdistribution_cleanup (procs de répli) peuvent être extrêmement consommatrices lorsque la file des requêtes à répliquer est très importante.</p>
<p>A+ [ 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/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
</ul>
<p><!-- Similar Posts took 1.432 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%2Fsql-server-sessions-consommatrices-dans-tempdb%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsql-server-sessions-consommatrices-dans-tempdb%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/5blcM1oSZzA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sql-server-sessions-consommatrices-dans-tempdb/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sql-server-sessions-consommatrices-dans-tempdb/</feedburner:origLink></item>
		<item>
		<title>Planification dans Adaptive Server</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/eQUClysRTos/</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> = &#8220;céder&#8221;). 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/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>
<li><a href="http://blog.capdata.fr/index.php/que-faire-des-warning-aborted-connection-avec-mysql/" rel="bookmark" title="25 mars 2010">Que faire des &#8220;[Warning] Aborted connection&#8221; avec MySQL ?</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 4.090 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" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/eQUClysRTos" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/</feedburner:origLink></item>
		<item>
		<title>Direct i/o, dsync on/off, raw device</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/eziRaETe154/</link>
		<comments>http://blog.capdata.fr/index.php/sybase-ase-direct-io-dsync-onoff-raw-device/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 15:20:11 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[Sybase]]></category>
		<category><![CDATA[directio]]></category>
		<category><![CDATA[dsync]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=148</guid>
		<description><![CDATA[Il y a depuis 2 ans et encore aujourd&#8217;hui un gros débat sur l&#8217;avenir du direct IO sur Linux dans la communauté des développeurs kernel (cf post Linus http://lkml.org/lkml/2007/1/10/233) . L&#8217;avenir du raw device lui ne se pose même plus puisque Red Hat ne le supporte plus que du bout des doigts (cf la manpage [...]]]></description>
			<content:encoded><![CDATA[<p>Il y a depuis 2 ans et encore aujourd&#8217;hui un gros débat sur l&#8217;avenir du direct IO sur Linux dans la communauté des développeurs kernel (cf post Linus <a title="LKML.org" href="http://lkml.org/lkml/2007/1/10/233"><em>http://lkml.org/lkml/2007/1/10/233</em></a>) . L&#8217;avenir du raw device lui ne se pose même plus puisque Red Hat ne le supporte plus que du bout des doigts (cf la manpage  de raw en RHEL5):</p>
<p><strong>WARNING</strong><br />
<em>Although  Linux  includes support for rawio, it is now a deprecated interface. If your application performs device access using this interface, Red Hat encourages you to modify your application to open the block device with the O_DIRECT flag. The rawio interface will exist for the life of Red Hat Enterprise Linux 5, but is a candi-<br />
date for removal from future releases.</em></p>
<p>Le bénéfice du raw device n&#8217;est pas nouveau, que ce soit pour Adaptive Server ou Oracle, le fait d&#8217;écrire directement sur la partition brute a deux avantages majeurs pour les SGBD:<br />
1 &#8211; Ca va plus vite.<br />
2 &#8211; Ca garantit que ce que l&#8217;on écrit va bien sur le disque et non dans un buffer en mémoire. En effet, le système de base de données gère lui-même la bufferisation de ses pages de données et d&#8217;indexes, et ne doit pas se reposer sur le système pour ça.</p>
<p>A partir du moment où le raw device cesse d&#8217;être supporté, on va devoir écrire dans un fichier, et qui dit écriture dans un fichier sous UNIX/Linux dit écriture bufferisée. C&#8217;est là où le critère 2 n&#8217;est plus garanti.</p>
<p>Il reste alors deux solutions qui vont nous permettre de garantir celà: DIRECTIO ou DSYNC. Ce sont en fait des arguments qui vont être passés à la primitive d&#8217;ouverture du fichier, le plus souvent open(), sous la forme de flags: O_DIRECT, O_DSYNC ou O_ASYNC.</p>
<p>A travers Adaptive Server, ces arguments seront manipulés lors de la création de devices avec la commande disk init:</p>
<pre>disk init name='PERFSTATS_data01', physname='/sybase_data/ASE1502/userdb/PERFSTATS_data01.dat',
size=512000,
directio=true</pre>
<p>ou</p>
<pre>disk init name='PERFSTATS_data01', physname='/sybase_data/ASE1502/userdb/PERFSTATS_data01.dat',
size=512000,
dsync=true</pre>
<p>On ne peut pas utiliser à la fois directio=true et dsync=true pour le même device, les options sont mutuellement exclusives.</p>
<p><strong>DIRECTIO</strong>:<br />
Lorsque directio est à true, le fichier PERFSTATS_data01.dat sera ouvert avec le flag O_DIRECT:</p>
<pre>open("/sybase_log/ASE1502/userdb/PERFSTATS_data01.dat", O_RDWR|O_SYNC|O_DIRECT|O_LARGEFILE) = 17</pre>
<p>Lorsque la primitive d&#8217;écriture est invoquée (write(), aiowrite()), l&#8217;écriture va directement sur le disque. Donc sémantiquement équivalent à ce que donne une écriture sur un raw device, à la fois en termes de performances et de garantie.</p>
<p><strong>DSYNC:</strong><br />
Lorsque dsync est à true, le fichier PERFSTATS_data01.dat sera ouvert avec le flag O_DSYNC:</p>
<pre>open("/sybase_log/ASE1502/userdb/PERFSTATS_data01.dat", O_RDWR|O_DSYNC|O_LARGEFILE) = 17</pre>
<p>Lorsque dsync est à false, le fichier PERFSTATS_data01.dat sera ouvert avec le flag O_ASYNC:</p>
<pre>open("/sybase_log/ASE1502/userdb/PERFSTATS_data01.dat", O_RDWR|O_ASYNC|O_LARGEFILE) = 17</pre>
<p>Lorsque la primitive d&#8217;écriture est invoquée, l&#8217;écriture sera bufferisée mais en fonction de la valeur passée à disk init (true  ou false),  certains éléments vont être synchronisés sur disque avant que aiowrite() ne revienne au programme appelant.<br />
<em><strong>- dsync=true</strong></em>: alors le flag O_DSYNC est passé à open(). Ce flag garantit que write() reste en attente tant que les données n&#8217;ont pas été synchronisées sur disque.<br />
<em><strong>- dsync=false:</strong></em> alors le flag O_ASYNC est passé à open(). Ce flag indique que write() rend la main une fois l&#8217;écriture bufferisée mais AVANT la synchronisation sur disque, ce qui ne garantit pas notre critère 2.</p>
<p>On recommandera toujours de mettre dsync=true pour les devices de données et de journaux pour avoir la garantie d&#8217;écriture stabilisée, et dsync=false pour les devices tempdb pour favoriser la perf.</p>
<p><strong>- Avantages / Inconvénients pour le DSYNC: </strong><br />
<em><strong>Avantages</strong></em>: c&#8217;est complètement supporté par les file system.<br />
<em><strong>Inconvénients</strong></em>: C&#8217;est moins performant en écriture.</p>
<p><strong>- Avantages / Inconvénients pour le DIRECTIO: </strong><br />
<em><strong>Avantages</strong></em>: c&#8217;est comme du raw device, sauf que c&#8217;est dans un fichier. C&#8217;est même plus efficace en lecture.<br />
<em><strong>Inconvénients</strong></em>: il faut que le filesystem le supporte (c&#8217;est le cas pour ext3), et d&#8217;après Linus l&#8217;implémentation de directio au niveau du kernel est épouvantable. Le problème c&#8217;est que ce qu&#8217;il indique comme contournement à destination des développeurs ASE (Wim Ten Have et Dave Wein en tête) n&#8217;est pas vraiment applicable.</p>
<p>Pas de doute, le DIRECTIO reste la meilleure option.  Ce sera sûrement réécrit un jour, mais pour l&#8217;instant on n&#8217;a pas trouvé mieux.</p>
<p>Un dernier mot sur le dsync=true sur les noyaux 2.6+, l&#8217;écriture asynchrone se transforme en écriture synchrone et les perfs chutent  <img src='http://blog.capdata.fr/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> (( . Il faut vraiment utiliser directio sur les noyaux récents. Ce sera peut être le sujet d&#8217;un prochain post sur ASE.</p>
<p>A+ [ 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/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/" rel="bookmark" title="5 juin 2009">Création et utilisation d&#8217;OCFS2</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 2.704 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-direct-io-dsync-onoff-raw-device%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsybase-ase-direct-io-dsync-onoff-raw-device%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/eziRaETe154" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sybase-ase-direct-io-dsync-onoff-raw-device/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sybase-ase-direct-io-dsync-onoff-raw-device/</feedburner:origLink></item>
		<item>
		<title>Règles d’installation de base (épisode 1)</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/1qQnhta3V5M/</link>
		<comments>http://blog.capdata.fr/index.php/sql-server-regles-dinstallation-de-base-episode-1/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 10:32:12 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[installation]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=130</guid>
		<description><![CDATA[C&#8217;est par là qu&#8217;on commence&#8230; à faire des bêtises en général. SQL Server, c&#8217;est facile, on clique, suivant, suivant et hop c&#8217;est fini.
Hélas, ce n&#8217;est pas plus facile qu&#8217;un autre SGBD. C&#8217;est juste plus facile de se tromper. Voici quelques règles de bases lorsqu&#8217;on s&#8217;apprête à installer un SQL Server en production. Episode 1: le [...]]]></description>
			<content:encoded><![CDATA[<p>C&#8217;est par là qu&#8217;on commence&#8230; à faire des bêtises en général. SQL Server, c&#8217;est facile, on clique, suivant, suivant et hop c&#8217;est fini.</p>
<p>Hélas, ce n&#8217;est pas plus facile qu&#8217;un autre SGBD. C&#8217;est juste plus facile de se tromper. Voici quelques règles de bases lorsqu&#8217;on s&#8217;apprête à installer un SQL Server en production. Episode 1: le matériel.</p>
<p><strong>1) La machine: physique ou virtuelle ? </strong><br />
Le gros débat des mois à venir. Même si la plupart des clients vont conserver des machines physiques pour leurs bases critiques, il y aura des bases de prod, uat, dev, qualif moins critiques qui seront virtualisées.<br />
Les constructeurs (Dell, HP,&#8230;) sortent de plus en plus des chassis dédiés à la virtualisation, avec ESXi embarqué. La virtualisation est (heureusement ? maheureusement ?) un train en marche, et plutôt que de freiner des quatre fers, posons-nous la question &#8220;comment virtualiser&#8221;, parce qu&#8217;il ne faut pas se voiler la face, on va y venir de toutes façons, ce n&#8217;est qu&#8217;une question de temps. HYPER-V et ESX sont tous les deux de bons concurrents, et ESX est annoncé compatible avec les produits MS. La combinaison des technos aujourd&#8217;hui (full virtualisation + assistance matérielle) fait que l&#8217;overhead de performances se réduit de plus en plus (on est quasiment en CPU-direct sur les Intel-VT et les AMD-V). Je penche personnellement pour le raw device mapping, une assistance matérielle CPU et une  configuration mémoire appropriée. Dans quelques temps nous aurons un ESX ou deux et nous pourrons tester tout ça.</p>
<p><strong>2) Admettons, machine physique:<br />
</strong><strong>LE PRIX ! </strong>Franchement les configurations à moins de 8000€ sont assez répandues et fiables. Je pense au HP Proliant DL 580 G5 (2&#215;4 Xeon 3Ghz, 4Gb RAM, 2 cartes 1ge et 16 slots disque pour $7600) ou au très populaire Dell PowerEdge 2950 III (même config mais avec seulement 6 slots disques pour $3600).</p>
<p><strong>DEDIEE/MUTUALISEE: </strong>en fonction des moyens. Mais idéalement il faut une machine dédiée. Les petits budgets vont faire tourner IIS et SQL Server sur la même machine, et d&#8217;expérience, c&#8217;est un mauvais calcul. Il vaut mieux investir un peu plus dans deux machines, et on aura moins de soucis ensuite.<br />
<strong><br />
CPU: </strong>le plus de cores il a sous le coude, et le mieux il se porte, SQL Server. Il est multithreadé, il sait parralléliser ses traitements. Evidemment il faut partir directement en 64 bits (EM64T, IA64, AMD64). Attention les éditeurs commencent à revoir leur politique de licence par socket, ils perdaient trop d&#8217;argent avec les hexacores et certains commencent à limiter à 6 cores par socket. Et attention à ne pas activer l&#8217;hyperthreading sur les machines SQL Server.<br />
<strong><br />
MEMOIRE: </strong>Oublier le 32 bits, la version 2008 de Windows Server sera la dernière à être proposée dans ce mode. En 64 bits, et avec le prix de la DDR2, il ne faut pas lésiner. C&#8217;est encore plus important que la CPU. Plus le cache de données est gros, moins SQL Server fera de lectures physiques.<br />
<strong><br />
RESEAU</strong>: Ca dépend. Je suis intervenu chez un client DRM il y a quelques temps et là le réseau c&#8217;était VRAIMENT crucial. Ca va le devenir de plus en plus avec FILESTREAM, la spatialisation, la vidéo HD, le plus de données on stocke, et le plus de données on va faire transiter. Les cartes et les core switches en 10Ge sont là, les Jumbo Frames, donc tout ça suit derrière. Le réseau entre systèmes Production / Secours est aussi crucial (Database mirroring, réplication). Nous avons un client en database mirroring 2005 qui avait installé un lien 100Mb entre ses deux sites, il va passer en fibre car il a de plus en plus de choses à faire passer sur le lien en plus du streaming lié au DB mirroring (sauvegardes, recopies de fichiers, etc&#8230;). Autre exemple, un client qui a une réplication transactionnelle entre Frankfort et Londres, le lien est vraiment très lent, et la resynchro de répli (34Gb) se fait en moyenne en 10-12 heures.<br />
Mais si l&#8217;application est codée en procédures stockées, que la quantité de données qui transite n&#8217;est pas importante et que SQL server est standalone, alors une carte 100Mb/s devrait faire l&#8217;affaire.<br />
<strong><br />
DISQUES: </strong>tout le monde ne peut pas se payer un SAN, je pense aux petites PME du web avec 1 machine serveur, un IIS  et une base de données de production, avec des moyens modestes. Donc on va considérer deux configurations: les disques internes pour les petits, et le stockage en réseau pour les riches et la classe moyenne.<br />
<em><strong> &#8211; DISQUES INTERNES</strong>:</em> choisir du SAS en 15KRPM. Le disque pour la base de données, c&#8217;est le nerf de la guerre. Le HP DL580 G5 avec ses 16 slots est parfait, il permet de faire trois RAID10 (data, log, backup) et un RAID1 (système) et de garder deux slots de spare. Il faudra vérifier au niveau de l&#8217;interface du contrôleur SAS que celui-ci est bien sur batterie et que celle-ci est valide, et que la politique est en write-through, c&#8217;est à dire que le cache du contrôleur n&#8217;est pas utilisé en écriture. Les disques SAS 73 Gb 15KRPM sont à 330€ chez Dell en 2&#8242;5, ça ne vaut pas le coup de se priver.<br />
<strong><em>- STOCKAGE RESEAU</em>: </strong>ne pas utiliser de NAS au sens strict (attachement réseau), pas de CIFS, ce n&#8217;est pas supporté de base par SQL Server. Il faut que les disques soient vus comme des disques locaux, donc soit une baie avec un attachement direct, soit un SAN. Pour les riches, le SAN en fibre channel est à privilégier. Pour la classe moyenne, le iSCSI est un bon moyen de faire du SAN à moindre coût, à la condition d&#8217;utiliser sur la machine hôte un initiateur matériel et non logiciel, c&#8217;est à dire une carte 1Ge qui soit compatible TSO (TCP Segmentation Offload, calcul de la pile TCP déchargée du CPU hôte), et que le réseau soit dédié au stockage. Pour les disques SAN, même politique que les disques internes. Au niveau du choix de la baie, il faut regarder plusieurs choses: Le nombre de storage processors (va déterminer le multiplexage des entrées, il en faut au moins 2), la  taille du cache par storage processor et non en globalité, le nombre de slots pour les disques, la capacité globale.  Le plus important c&#8217;est la taille du cache par SP.  Si les caches entre SP sont mirrorés l&#8217;un sur l&#8217;autre, on perd la moitié de la capacité  mémoire, si la baie est mirorrée sur une autre, on perd encore car le soft de miroir utilise des buffers dans le cache de chaque SP.  Ensuite, il faut voir comment le cache est partitionné entre les lectures et les écritures. Le plus souvent, c&#8217;est fait à la louche pour des systèmes majoritairement en lecture, mais attention à ne pas négliger les écritures en transactionnel. Un cache en écriture plein, et les queues se remplissent au niveau des SP, on observe des outstanding IOs côté SQL Server et c&#8217;est rapidement la cata.</p>
<p>Il paraît que je fais des articles trop longs, donc ce sera tout pour aujourd&#8217;hui <img src='http://blog.capdata.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /><br />
Prochain épisode, l&#8217;installation Windows et les prérequis SQL Server.</p>
<p>A+ [ 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/mythe-torn-page-detection-est-moins-couteux-que-checksum/" rel="bookmark" title="1 septembre 2010">Mythe: TORN PAGE DETECTION est moins coûteux que CHECKSUM</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/un-trigger-fait-il-parti-dune-transaction/" rel="bookmark" title="30 mars 2010">Un trigger fait-il parti d&#8217;une transaction ?</a> (Cédric PEINTRE) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/" rel="bookmark" title="15 juillet 2010">Attention aux requêtes en double avec Windev et MySQL !</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/mythe-sql-server-associe-un-thread-a-chaque-connexion/" rel="bookmark" title="1 août 2010">Mythe: SQL Server associe un thread à chaque connexion</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/fragmentation-sur-des-tables-stockees-en-s-gam/" rel="bookmark" title="20 août 2010">Fragmentation sur des tables stockées en S-GAM</a> (David BAFFALEUF) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.896 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%2Fsql-server-regles-dinstallation-de-base-episode-1%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsql-server-regles-dinstallation-de-base-episode-1%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/1qQnhta3V5M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sql-server-regles-dinstallation-de-base-episode-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sql-server-regles-dinstallation-de-base-episode-1/</feedburner:origLink></item>
		<item>
		<title>Attention : publication transactionnelle et indexes non clusters</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/ozjPLSWfpKc/</link>
		<comments>http://blog.capdata.fr/index.php/replication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 08:28:06 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[replication]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=125</guid>
		<description><![CDATA[Récemment, en resynchronisant une publication transactionnelle avec un éditeur 2005 vers un abonné 2005, on s&#8217;est aperçu que le snapshot ne générait que les index clusters pour chaque article, pas les indexes non clusters. Enorme ! Nous avons revérifié avec un éditeur en 2000, et les indexes non clusters sont bien générés en même temps [...]]]></description>
			<content:encoded><![CDATA[<p>Récemment, en resynchronisant une publication transactionnelle avec un éditeur 2005 vers un abonné 2005, on s&#8217;est aperçu que le snapshot ne générait que les index clusters pour chaque article, pas les indexes non clusters. Enorme ! Nous avons revérifié avec un éditeur en 2000, et les indexes non clusters sont bien générés en même temps que les clusters.</p>
<p><strong>Explication: </strong>lorsque l&#8217;agent de snapshot doit extraire le DDL des articles et sortir les données par bcp en parrallèle, il se base sur deux options passées lors du sp_addarticle:<br />
- <strong>@type</strong>: qui va indiquer à quel type de publication on a affaire. Dans notre cas, ce sera <em><strong>logbased </strong></em>(=transac)<br />
- <strong>@schema_option</strong> : bitmask qui va indiquer ce qui doit être généré au niveau DDL.</p>
<p>D&#8217;après les BOLs 2005, si <strong>@type = &#8216;logbased&#8217;</strong>, alors <strong>@schema_option</strong> doit être à <strong>0&#215;30F3</strong>, qui décomposé contient bien à la fois le bitmask pour les index clusterisés (0&#215;10) et celui pour les indexes NC (0&#215;40).</p>
<p>Je vous engage à tester ça depuis SSMS, en créant une publication transac bidon et en jetant un coup d&#8217;oeil aux propriétés de l&#8217;article:</p>
<p><a href="https://www.alldb.fr/blog/wp-content/uploads/2009/06/moz-screenshot-176.jpg"><img class="alignnone size-medium wp-image-126" src="https://www.alldb.fr/blog/wp-content/uploads/2009/06/moz-screenshot-176-269x300.jpg" alt="" /></a></p>
<p>Dans le script généré, effectivement on a bien un problème:</p>
<p><tt>exec    sp_addarticle<br />
@publication = N'pubtest1',</tt><tt><br />
@article =    N'Address',<br />
</tt><tt> </tt><tt>@source_owner = N'dbo',<br />
</tt><tt> </tt><tt>@source_object = N'Address',<br />
<strong>@type = N'logbased'</strong>,<br />
</tt><tt> </tt><tt>@description = null,<br />
</tt><tt> </tt><tt>@creation_script = null,<br />
</tt><tt> </tt><tt>@pre_creation_cmd = N'drop',<br />
<strong>@schema_option = 0x000000000803509F</strong>,<br />
</tt><tt> </tt><tt>@identityrangemanagementoption =    N'manual',<br />
</tt><tt> </tt><tt>@destination_table = N'Address',<br />
@destination_owner = N'dbo',<br />
</tt><tt> </tt><tt>@vertical_partition = N'false',<br />
</tt><tt> </tt><tt>@ins_cmd = N'CALL    sp_MSins_dbo</tt><tt>Address</tt><tt>',<br />
@del_cmd =    N'CALL sp_MSdel_dbo</tt><tt>Address</tt><tt>',<br />
</tt><tt> </tt><tt>@upd_cmd = N'SCALL    sp_MSupd_dbo</tt><tt>Address</tt><tt>'<br />
GO</tt></p>
<p>Le bitmask 0&#215;803509F contient bien le 0&#215;10, mais pas le 0&#215;40.  Pour en avoir le coeur net, utilisez le ET logique  en transac (<tt>134434975=0x803509, 64=0x40, 16=0x10):</tt></p>
<p><tt>select 134434975 &amp;    64<br />
select 134434975 &amp; 16</tt></p>
<p><tt>-----------<br />
0</tt></p>
<p><tt>-----------<br />
16<br />
</tt><br />
Suite à une petite discussion avec Paul Randal, il se trouve que nombre de ses clients ont eu le même problème en migrant. Donc si vous migrez une réplication de 2000 vers 2005, et que vous constatez des problèmes de perfs sur les abonnés, vérifiez si vous avez tous vos indexes NC, juste comme ça&#8230; <img src='http://blog.capdata.fr/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>A+ [ David B. ]<br />
<tt><br />
</tt><br />
 <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/replication-sql-server-retrouver-la-vilaine-transaction-en-echec/" rel="bookmark" title="21 septembre 2009">Retrouver une transaction en échec</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/attention-aux-requetes-en-double-avec-windev-et-mysql/" rel="bookmark" title="15 juillet 2010">Attention aux requêtes en double avec Windev et MySQL !</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/xtradb-sauvegarde-votre-cache-et-ca-marche/" rel="bookmark" title="9 mars 2010">XtraDB sauvegarde votre cache, et ça marche !</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/mysql-et-les-tables-temporaires-internes/" rel="bookmark" title="6 janvier 2010">MySQL et les tables temporaires internes</a> (Cédric PEINTRE) [MySQL]</li>
<li><a href="http://blog.capdata.fr/index.php/insert-et-update-en-une-seule-fois-cest-possible-merge/" rel="bookmark" title="26 mars 2010">Insert et Update en une seule fois avec MERGE</a> (Guillaume DEFENDINI) [SQL Server]</li>
</ul>
<p><!-- Similar Posts took 3.779 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%2Freplication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Freplication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/ozjPLSWfpKc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/replication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/replication-sql-server-attention-publication-transactionnelle-et-indexes-non-clusters/</feedburner:origLink></item>
		<item>
		<title>Création et utilisation d’OCFS2</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/Q_83QiUcq64/</link>
		<comments>http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 14:26:12 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[CFS]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[OCFS2]]></category>
		<category><![CDATA[rac]]></category>
		<category><![CDATA[suse]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=103</guid>
		<description><![CDATA[Cet article est écrit par Thierry GASCARD.

Nous allons créer un système de fichiers supportant le cluster (Cluster FileSystem).
L&#8217;OS utilisé est une SUSE 10 en 64 bits.
1. Installation du driver OCFS2
A effectuer via l’utilisateur système root.
OCFS2 1.4 est compris dans la distribution SLES10 SP2.
sinon sous les autres linux :
Déterminer la version du noyau : uname –rm
Rechercher [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est écrit par <a href="mailto:tgascard@capdata.fr" target="_blank">Thierry GASCARD.<br />
</a></p>
<p>Nous allons créer un système de fichiers supportant le cluster (Cluster FileSystem).<br />
L&#8217;OS utilisé est une SUSE 10 en 64 bits.</p>
<h1>1. Installation du driver OCFS2</h1>
<p>A effectuer via l’utilisateur système root.<br />
OCFS2 1.4 est compris dans la distribution SLES10 SP2.<br />
sinon sous les autres linux :<br />
Déterminer la version du noyau : uname –rm<br />
Rechercher les drivers sur le site d’<a href="http://oss.oracle.com/projects/ocfs2/" target="_blank">Oracle</a><br />
Télécharger les fichiers correspondants à la plate forme et la version du noyau (ici RH5 64 bits)</p>
<ul>
<li>ocfs2-tools-1.4.1-1.el5.x86_64.rpm</li>
<li>ocfs2console-1.4.1-1.el5.x86_64.rpm</li>
<li>ocfs2-2.6.18-128.1.1.el5-1.4.1-1.el5.x86_64.rpm</li>
</ul>
<p>Installer les RPMs sur chaque noeud :<br />
<em>rpm -Uvh ocfs2*.rpm</em><br />
vérifier l’installation<br />
<em> chkconfig &#8211;list o2cb</em></p>
<h1>2. Configuration OCFS2</h1>
<p>1) Sur un des nœuds en x window lancer ocfs2console puis cluster/configure node<br />
ajouter hostname1   x.x.x<br />
ajouter hostname2   x.x.x<br />
puis propager la configuration<br />
Rem : attention au nom de domaine<br />
2) vérifier sur chaque nœud le fichier /etc/ocfs2/cluster.conf<br />
3) configurer le service o2cb sur chaque nœud en root<br />
<em>/etc/init.d/o2cb configure </em></p>
<p>puis répondre y et accepter les valeurs par défaut sauf Use user-space driven heartbeat? (y/n) [y] n</p>
<h1>3. Formater la partition en OCFS2 sur un nœud</h1>
<p>en x window lancer ocfs2console  puis task/format</p>
<ul>
<li> /dev/emcpowerd</li>
<li> label : oracle</li>
<li> cluster size : 128 K</li>
<li> block size 4k</li>
</ul>
<h1>4. Monter le système de fichiers OCFS2</h1>
<p>1) créer un point de montage sur chaque nœud<br />
<em>mkdir /ocfs</em><br />
2) ajouter dans /etc/fstab, voire la note metalink <span style="helvetica;"><strong>835839.1</strong></span><br />
/dev/emcpowerd /ocfs    ocfs2    _netdev,datavolume,nointr,noatime 0 0</p>
<p>les options correspondent avec ocfs2 1.4.1  :</p>
<ul>
<li> datavolume : utilisation des &#8220;direct IO&#8221;</li>
<li> _netdev : montage après le réseau</li>
<li> nointr: désactive les siganux durant les opération de cluster</li>
<li>noatime : désactive la mise à jour de l&#8217;heure</li>
</ul>
<p><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/" rel="bookmark" title="5 juin 2009">Installation Oracle 64 bits sur Red Hat 5</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/" rel="bookmark" title="12 juin 2008">Se connecter à SQL Server à travers Oracle, quelle drôle d&#8217;idée ?</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/" rel="bookmark" title="3 mars 2010">Installation Oracle 11gR2 64 bits sur Red Hat 5 Partie 1</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/utiliser-asmcmd/" rel="bookmark" title="5 juin 2009">Utiliser ASMCMD</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 3.847 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%2Fcreation-et-utilisation-docfs2%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fcreation-et-utilisation-docfs2%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/Q_83QiUcq64" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/</feedburner:origLink></item>
		<item>
		<title>Utiliser ASMCMD</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/ada4ENdmFyk/</link>
		<comments>http://blog.capdata.fr/index.php/utiliser-asmcmd/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 13:55:30 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[asm]]></category>
		<category><![CDATA[asmcmd]]></category>
		<category><![CDATA[cluster]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=97</guid>
		<description><![CDATA[Cet article est écrit par Vincent Devers
Un utilitaire asmcmd permet de naviguer dans les disques ASM.
Voici quelques commandes utiles.
Avant de se connecter, vérifier que les processus de l’instance ASM sont lancés
 ps –ef &#124;grep ASM
export ORACLE_SID=+ASM
export ORACLE_HOME=/u01/app/asm/asm_1
Afficher la version : asmcmd –v 
Lancer asmcmd sous l&#8217;utilisateur asm ou oracle
Asmcmd&#62;
Lister les disques groupes ( affiche également [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est écrit par <a href="mailto:vdevers@capdata.fr">Vincent Devers</a></p>
<p>Un utilitaire asmcmd permet de naviguer dans les disques ASM.<br />
Voici quelques commandes utiles.<br />
Avant de se connecter, vérifier que les processus de l’instance ASM sont lancés<br />
<em> ps –ef |grep ASM<br />
export ORACLE_SID=+ASM<br />
export ORACLE_HOME=/u01/app/asm/asm_1</em></p>
<p>Afficher la version : <em>asmcmd –v </em><br />
Lancer <em>asmcmd </em>sous l&#8217;utilisateur asm ou oracle<br />
Asmcmd&gt;<br />
Lister les disques groupes ( affiche également la taille des disques et l’espace libre dans les disques ) : <strong>lsdg</strong><br />
Lister les disques : <strong>lsdsk</strong><br />
Avoir les io sur les disques : <strong>lsdsk -s</strong><br />
Vérifier le status des disques : <strong>lsdsk –p</strong><br />
Aller dans un groupe :  <strong>cd </strong>+diskgroup1/<br />
Afficher l’espace total utilisé : du<br />
Trouver tous les fichiers d’un type dans un diskgroup :<br />
<strong>find –t</strong> archivelog  + DISKGROUP1/ *<br />
<strong> find –t</strong> datafile +DISKGROUP1/  *<br />
<strong>find –t</strong> onlinelog +DISKGROUP1/ *<br />
<strong>find –t </strong>tempfile +DISKGROUP1/ *<br />
<strong> find –t </strong>backupset +DISKGROUP1/  *<br />
<strong> find –t</strong> parameterfile +DISKGROUP1/  *<br />
<strong>find –t</strong> dataguardconfig + DISKGROUP1/  *<br />
<strong>find –t</strong> flashback +DISKGROUP1/ *<br />
<strong>find –t </strong>dumpset + DISKGROUP1/  *<br />
Trouver les fichiers sans le type mais avec une wildcard : <strong>find </strong>+DISKGROUP1/  undo*<br />
Créer une sauvegarde contenant les métadonnées pour un ou plusieurs groupes  :<br />
<strong>md_backup –b</strong> /u01/bdd/backupall<br />
<strong>md_backup –b</strong> /u01/bdd/backupdiskgroup1 –g diskgroup1<br />
Restaurer des métadonnées d’un diskgroup :<br />
<strong>md_restore –b</strong> backup_file ( lit les métadata de backup_file )<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/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/" rel="bookmark" title="3 mars 2010">Installation Oracle 11gR2 64 bits sur Red Hat 5 Partie 1</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/" rel="bookmark" title="5 juin 2009">Création et utilisation d&#8217;OCFS2</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/" rel="bookmark" title="12 juin 2008">Se connecter à SQL Server à travers Oracle, quelle drôle d&#8217;idée ?</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/" rel="bookmark" title="5 juin 2009">Installation Oracle 64 bits sur Red Hat 5</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 3.924 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%2Futiliser-asmcmd%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Futiliser-asmcmd%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/ada4ENdmFyk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/utiliser-asmcmd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/utiliser-asmcmd/</feedburner:origLink></item>
		<item>
		<title>Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/5_cYGxH644s/</link>
		<comments>http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 13:14:14 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[asm]]></category>
		<category><![CDATA[asmlib]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[EMC]]></category>
		<category><![CDATA[Powerpath]]></category>
		<category><![CDATA[suse]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=89</guid>
		<description><![CDATA[Cet article est écrit par Thierry GASCARD.
1. Installation et configuration du driver ASMLIB
Sous l&#8217;utilisateur root
1.1    Installation ASMLIB
- Déterminer la version du noyau : uname –rm
- Rechercher les drivers ASM sur le site d’Oracle
- Télécharger les fichiers correspondants à la plate forme et la version du noyau
oracleasm-support-2.1.3-1.SLE10.x86_64.rpm
oracleasmlib-2.0.4-1.SLE10.x86_64.rpm
oracleasm-2.6.16.60-0.39.3-smp-2.0.5-1.SLE10.x86_64.rpm
- Installer les RPM correspondants :
rpm -Uvh \
&#62; oracleasm-2.6.16.60-0.39.3-smp-2.0.5-1.SLE10.x86_64.rpm \
&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est écrit par <a href="mailto:tgascard@capdata.fr" target="_blank">Thierry GASCARD.</a></p>
<h1>1. Installation et configuration du driver ASMLIB</h1>
<p>Sous l&#8217;utilisateur root</p>
<h2>1.1    Installation ASMLIB</h2>
<p>- Déterminer la version du noyau : uname –rm<br />
- Rechercher les drivers ASM sur le site d’<a href="http://www.oracle.com/technology/software/tech/linux/asmlib/sles10.html" target="_blank">Oracle</a><br />
- Télécharger les fichiers correspondants à la plate forme et la version du noyau<br />
oracleasm-support-2.1.3-1.SLE10.x86_64.rpm<br />
oracleasmlib-2.0.4-1.SLE10.x86_64.rpm<br />
oracleasm-2.6.16.60-0.39.3-smp-2.0.5-1.SLE10.x86_64.rpm<br />
- Installer les RPM correspondants :<br />
<em>rpm -Uvh \<br />
&gt; oracleasm-2.6.16.60-0.39.3-smp-2.0.5-1.SLE10.x86_64.rpm \<br />
&gt; oracleasmlib-2.0.4-1.SLE10.x86_64.rpm \<br />
&gt; oracleasm-support-2.1.3-1.SLE10.x86_64.rpm</em></p>
<h2>1.2 Configuration du driver ASM</h2>
<p>- Lancer la commande de configuration<br />
<em># /etc/init.d/oracleasm configure</em><br />
- Renseigner les informations suivantes :<br />
<em>Default user to own the driver interface []: oracle<br />
Default group to own the driver interface []: dba<br />
Start Oracle ASM library driver on boot (y/n) [n]: y<br />
Fix permissions of Oracle ASM disks on boot (y/n) [y]: y<br />
Writing Oracle ASM library driver configuration:           [  OK  ]<br />
Creating /dev/oracleasm mount point:                       [  OK  ]<br />
Loading module &#8220;oracleasm&#8221;:                                [  OK  ]<br />
Mounting ASMlib driver filesystem:                         [  OK  ]<br />
Scanning system for ASM disks :                            [  OK  ]</em></p>
<h2>1.3 Créer les volumes ASM</h2>
<p><em>/usr/sbin/asmtool -C -l /dev/oracleasm -n VOLDB1-s /dev/emcpowerb -a force=yes<br />
/usr/sbin/asmtool -C -l /dev/oracleasm -n VOLBK1 -s /dev/emcpowerc -a force=yes</em><br />
puis redémarrer le serveur</p>
<p>Rem : oracleasm createdisk ne fonctionne pas note Metalink : <span style="helvetica;"><strong>469163.1</strong></span><br />
erreur de reconnaissance des disques fournis avec powerpath<br />
<em># /etc/init.d/oracleasm createdisk VOLDB1 /dev/emcpowerb<br />
Marking disk &#8220;/dev/emcpowerb&#8221; as an ASM disk: asmtool: Device &#8220;/dev/emcpowerb&#8221; is not a partition<br />
[FAILED]</em></p>
<h2>1.3 Vérifier</h2>
<p>lancer la découverte<br />
<em>/etc/init.d/oracleasm scandisks</em><br />
Vérifier l’existence des volumes sur les deux noeuds<br />
<em># /etc/init.d/oracleasm listdisks</em></p>
<h2>1.4 configurer les chemins de découverte des disques</h2>
<p>Modifier le fichier /etc/sysconfig/oracleasm pour paramétrer la gestion du  &#8220;multipathing&#8221; en gras :</p>
<p>..<br />
# ORACLEASM_SCANORDER: Matching patterns to order disk scanning<br />
ORACLEASM_SCANORDER=&#8221;<strong>emcpower</strong>&#8221;</p>
<p># ORACLEASM_SCANEXCLUDE: Matching patterns to exclude disks from scan<br />
ORACLEASM_SCANEXCLUDE=&#8221;<strong>sd</strong>&#8221;</p>
<h2>2. Installation ASM 11g</h2>
<p>Dans son propre ORACLE_HOME (ORACLE_ASM_HOME)</p>
<h1>3. Passage patch 11.1.0.7</h1>
<h1>4. Création de l’instance ASM</h1>
<h2>4.1. Configuration du listener pour ASM</h2>
<p>Connexion avec l’utilisateur asm ou oracle sinon<br />
<em>export ORACLE_HOME=/u01/app/asm/11.1.0/asm_1<br />
$ORACLE_HOME/admin/netca &amp;</em><br />
Creation du listener LISTENER_ASM sur le port 1521 en TCP</p>
<h2>4.2 Création de l&#8217;instance ASM</h2>
<p>Connexion avec l’utilisateur système oracle<br />
export ORACLE_SID=+ASM1<br />
/u01/oracle/11g/asm/bin/dbca &amp;</p>
<p>puis configurer les &#8220;disques groupe&#8221;<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/" rel="bookmark" title="5 juin 2009">Installation Oracle 64 bits sur Red Hat 5</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/" rel="bookmark" title="3 mars 2010">Installation Oracle 11gR2 64 bits sur Red Hat 5 Partie 1</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/" rel="bookmark" title="5 juin 2009">Création et utilisation d&#8217;OCFS2</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 4.047 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%2Finstallation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Finstallation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/5_cYGxH644s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/</feedburner:origLink></item>
		<item>
		<title>Installation Oracle 64 bits sur Red Hat 5</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/ef0nuHwz2gg/</link>
		<comments>http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 10:25:29 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[64 bits]]></category>
		<category><![CDATA[huge page]]></category>
		<category><![CDATA[redhat 5]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=72</guid>
		<description><![CDATA[Cet article est écrit par Thierry GASCARD.
1 Configuration système
1.1 Pré-requis matériel :
- 12 Go pour les binaires Oracle en RAID 10
- 400 Mo sur /tmp
1.2 Pré-requis logiciel :
RH 5 Entreprise 64 Bits : Oracle 10.2.0.1 Entreprise Edition Linux x86-64
Patch 10.2.0.4 pour Linux x86-64 sur le site du support Oracle 
Patch 6620371 pour Linux 64 Bits [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est écrit par <a href="mailto:tgascard@capdata.fr" target="_blank">Thierry GASCARD.</a></p>
<h1>1 Configuration système</h1>
<h2>1.1 Pré-requis matériel :</h2>
<p>- 12 Go pour les binaires Oracle en RAID 10<br />
- 400 Mo sur /tmp</p>
<h2>1.2 Pré-requis logiciel :</h2>
<p>RH 5 Entreprise 64 Bits<a href="http://www.oracle.com/technology/software/products/database/index.html" target="_blank"> : Oracle 10.2.0.1 Entreprise Edition Linux x86-64</a></p>
<p>Patch 10.2.0.4 pour Linux x86-64 sur le site du <a href="http://metalink.oracle.com" target="_blank">support Oracle </a></p>
<p>Patch 6620371 pour Linux 64 Bits sur le site du <a href="http://metalink.oracle.com">support Oracle </a></p>
<h2>1.3 Pré-requis noyau</h2>
<p>version du noyau &gt;=2.6.18-8<br />
SELinux désactivé<br />
X installé et configuré<br />
Rpms suivants installés en plus des Rpms par défaut (version minimum) :<br />
binutils-2.17.50 (x86_64)<br />
compat-db-4.2.52 (x86_64)<br />
compat-libstdc++-296(i386)<br />
compat-libstdc++-33-3.2.3 (x86_64)<br />
compat-libstdc++-33-3.2.3(i386)<br />
control-center-2.16.0 (x86_64)<br />
gcc-4.1.1 (x86_64)<br />
gcc-c++-4.1.1 (x86_64)<br />
glibc-2.5-12 (x86_64)<br />
glibc-2.5-12 (i686)<br />
glibc-common-2.5-12 (x86_64)<br />
glibc-devel-2.5-12 (x86_64)<br />
glibc-devel-2.5-12(i386)<br />
glibc-headers-2.5-12 (x86_64)<br />
ksh-20060214-1.4 (x86_64)<br />
libaio-0.3.96 (x86_64)<br />
libgcc-4.1.1(i386)<br />
libgcc-4.1.1(x86_64)<br />
libgnome-2.16.0 (x86_64)<br />
libgnomeui-2.16.0 (x86_64)<br />
libgomp-4.1.1 (x86_64)<br />
libstdc++-4.1.1 (x86_64)<br />
libstdc++-devel-4.1.1 (x86_64)<br />
libXp-1.0.0-8 (i386)<br />
make-3.81 (x86_64)<br />
sysstat-7.0.0 (x86_64)<br />
unixODBC-2.2.11-7.1 x86_64.<br />
unixODBC-devel-2.2.11-7.1 x86_64<br />
util-linux-2.13-0.50.el5 x86_64<br />
xorg-x11-xinit-1.0.2-15.el5 x86_64</p>
<p>Rem : attention à la présence de rpms 32 bits : utilisation possible de l&#8217;option force : <em>rpm -ivh &#8211;force</em> ..</p>
<h2>1.4 Paramètres noyau</h2>
<p>Modification du fichier <strong>/etc/sysctl.conf</strong> :<br />
kernel.shmmni = 4096<br />
kernel.sem= 250 32000 100 128<br />
kernel.sysrq=1<br />
kernel.msgmnb=65536<br />
kernel.msgmni=2878<br />
kernel.msgmax=8192<br />
net.ipv4.ip_local_port_range = 9000 65500<br />
net.core.rmem_default = 262144<br />
net.core.rmem_max=2097152<br />
net.core.wmem_default = 262144<br />
net.core.wmem_max = 262144<br />
fs.aio-max-nr=3145728<br />
fs.file-max=327679<br />
vm.lower_zone_protection=100<br />
kernel.shmall = 3145728<br />
kernel.shmmax = 12884901888<br />
vm.nr_hugepages = 6144</p>
<p>Modification du fichier <strong>/etc/security/limits.conf</strong> :<br />
oracle hard memlock 12582912<br />
oracle soft memlock 12582912<br />
oracle soft core unlimited<br />
oracle hard nofile 131072<br />
oracle hard nproc 131072<br />
oracle soft nproc 131072<br />
oracle soft nofile 131072<br />
oracle hard core unlimited</p>
<h1>2    Préparation système</h1>
<h2>2.1 Création groupe oinstall,dba</h2>
<p><em>root&gt; groupadd -g 55 oinstall<br />
root&gt;groupadd -g 56 dba</em></p>
<h2>2.2    Ajout utilisateur oracle</h2>
<p><em>root&gt; useradd -u 500 -g 55 -G dba -c &#8220;Oracle Owner&#8221; -d /home/oracle -s /bin/bash oracle<br />
root&gt; passwd oracle</em></p>
<p>2.2 Modification du fichier<strong> /etc/profile</strong><br />
if [ $USER = "oracle" ]; then<br />
if [ $SHELL = "/bin/ksh" ]; then<br />
ulimit -p 16384<br />
ulimit -n 65536<br />
ulimit -l 12582912<br />
else<br />
ulimit -u 16384 -n 65536 -l 12582912<br />
fi<br />
fi</p>
<h2>2.2    Création des répertoires</h2>
<p><em>root&gt; mkdir /opt/oracle<br />
root&gt; mkdir /u01<br />
root&gt; chown –R oracle:oinstall /opt/oracle<br />
root&gt; chown –R oracle:oinstall /u01<br />
root&gt; su &#8211; oracle<br />
mkdir -p /opt/oracle/product/10.2.0/db_1<br />
mkdir -p /opt/oracle/admin</em></p>
<h2>3 Installation Oracle</h2>
<h2>3.1    Décompression des zips et cpio</h2>
<p><em>$ cat 10201_database_linux_x86_64.cpio.gz | gunzip | cpio -idvm<br />
$ cat 10201_companion_linux_x86_64.cpio.gz | gunzip | cpio –idvm<br />
$unzip p6810189_10204_Linux-x86-64</em></p>
<h2>3.2   installation</h2>
<p><em>export ORACLE_BASE=/opt/oracle/product ;<br />
export ORACLE_HOME=/opt/oracle/product/10.2.0/db_1<br />
./runInstaller &amp;</em></p>
<p>Ordre d’installation<br />
1. Installation &#8220;Base Product (10.2.0.1)&#8221;<br />
2. Installation “Companion Disk” pour éviter l’erreur NCOMP lors du patch 10.2.0.4<br />
- Choisir l’option «Oracle Database 10g Products 10.2.0.1.0»<br />
3. Installation Patch (10.2.0.4)<br />
4. Installation patch 6620371 pour &#8220;huge page&#8221;<br />
<em> [oracle]$ cd 6620371/<br />
[oracle]$ /opt/oracle/product/10.2.0/db_1/OPatch/opatch apply</em></p>
<h1>4    Mise à jour de l’environnement Oracle</h1>
<h2>4.1 mise à jour du .profile_bash d&#8217;oracle</h2>
<h2>4.2 mise à jour du glogin.sql</h2>
<p>vi $ORACLE_HOME/slplus/admin/glogin.sql<br />
set sqlprompt &#8220;_user &#8216;on&#8217; _date &#8216;at&#8217; _connect_identifier &gt;&#8221;</p>
<h1>5    configuration de huge page sous linux</h1>
<p>- vm.nr_hugepages  : nombre de pages (taille de 2Mo sur linux avec grep Hugepagesize /proc/meminfo)<br />
- vm.hugetlb_shm_group : ID du groupe utilisé par oracle (dba)<br />
- kernel.shmmax supérieur à la taille de l&#8217;espace mémoire accordé aux &#8220;huge page&#8221;<br />
- memlock  : avec /etc/security/limit.conf et ulimit -l<br />
Tout est bien expliqué dans le blog d&#8217; <a href="http://arkzoyd.blogspot.com/2008/10/huge-pages-linux-et-oracle.html" target="_blank">arkzoyd</a>: à lire absolument !!!!!<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/" rel="bookmark" title="5 juin 2009">Création et utilisation d&#8217;OCFS2</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/" rel="bookmark" title="3 mars 2010">Installation Oracle 11gR2 64 bits sur Red Hat 5 Partie 1</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/" rel="bookmark" title="12 juin 2008">Se connecter à SQL Server à travers Oracle, quelle drôle d&#8217;idée ?</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/utiliser-asmcmd/" rel="bookmark" title="5 juin 2009">Utiliser ASMCMD</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 3.857 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%2Finstallation-oracle-64-bits-sur-red-hat-5%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Finstallation-oracle-64-bits-sur-red-hat-5%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/ef0nuHwz2gg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/</feedburner:origLink></item>
		<item>
		<title>Principes d’une sauvegarde à chaud</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/weK0hjIbcTI/</link>
		<comments>http://blog.capdata.fr/index.php/sql-server-principes-dune-sauvegarde-a-chaud/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 15:00:47 +0000</pubDate>
		<dc:creator>David BAFFALEUF</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[backup database]]></category>
		<category><![CDATA[checkpoint]]></category>

		<guid isPermaLink="false">https://www.alldb.fr/blogs/?p=47</guid>
		<description><![CDATA[Rien de plus simple de que faire une sauvegarde sur SQL Server:
BACKUP DATABASE maBase to disk='D:\MSSQL.1\MSSQL\Backup\maBase.bak' with init, stats
10 percent processed.
21 percent processed.
32 percent processed.
43 percent processed.
54 percent processed.
60 percent processed.
71 percent processed.
82 percent processed.
93 percent processed.
Processed 144 pages for database 'maBase', file 'maBase' on file 1.
100 percent processed.
Processed 2 pages for database 'maBase', file [...]]]></description>
			<content:encoded><![CDATA[<p><span>Rien de plus simple de que faire une sauvegarde sur SQL Server:</span></p>
<pre><span lang="EN-GB">BACKUP DATABASE maBase to disk='D:\MSSQL.1\MSSQL\Backup\maBase.bak' with init, stats</span></pre>
<pre><span lang="EN-GB">10 percent processed.</span></pre>
<pre><span lang="EN-GB">21 percent processed.</span></pre>
<pre><span lang="EN-GB">32 percent processed.</span></pre>
<pre><span lang="EN-GB">43 percent processed.</span></pre>
<pre><span lang="EN-GB">54 percent processed.</span></pre>
<pre><span lang="EN-GB">60 percent processed.</span></pre>
<pre><span lang="EN-GB">71 percent processed.</span></pre>
<pre><span lang="EN-GB">82 percent processed.</span></pre>
<pre><span lang="EN-GB">93 percent processed.</span></pre>
<pre><span lang="EN-GB">Processed 144 pages for database 'maBase', file 'maBase' on file 1.</span></pre>
<pre><span lang="EN-GB">100 percent processed.</span></pre>
<pre><span lang="EN-GB">Processed 2 pages for database 'maBase', file 'maBase_log' on file 1.</span></pre>
<pre><span lang="EN-GB">BACKUP DATABASE successfully processed 146 pages in 0.816 seconds (1.463 MB/sec).</span></pre>
<p><span>Et voilà. L&#8217;avantage d&#8217;une telle sauvegarde est que je peux la lancer sans stopper mon service, sous entendu avec de l&#8217;activité: connexions utilisateurs, transactions en cours, etc&#8230; Et tout ça en me garantissant de restaurer une base transactionnellement cohérente. Pour y parvenir, elle commence par sauvegarder les données puis les transactions présentes dans le journal.</span></p>
<p><span>Avant de parler de ce que fait le BACKUP DATABASE, il faut parler un peu des rôles respectifs du <strong>CHECKPOINT </strong>et du <strong>COMMIT </strong>dans le processus de RECOVERY.</span></p>
<p class="MsoNormal"><!--[if !supportLists]--><span><span>i)<span> </span></span></span><!--[endif]--><span dir="ltr"><span>Lorsqu’un utilisateur initie une transaction, ses modifications sont d’abord journalisées en mémoire dans une zone qui est réservée pour sa session. Puis les pages de données et d’index concernées sont modifiées dans le cache de données. </span></span></p>
<p class="MsoNormal"><!--[if !supportLists]--><span><span>ii)<span> </span></span></span><!--[endif]--><span dir="ltr"><span>Lorsqu’il valide sa transaction de manière implicite ou explicite (avec COMMIT TRANSACTION), le contenu de son journal de session est enregistré physiquement dans le fichier LDF. Il est impératif de s’assurer que le COMMIT ne peut rendre la main à la commande appelante que lorsque la transaction a été véritablement écrite sur disque (le ‘write-ahead logging’ en d’autres termes). Ce mécanisme permet de pouvoir récupérer la transaction validée lorsqu’un problème survient avant que les pages de données n’aient pu être écrites.</span></span></p>
<p class="MsoNormal"><!--[if !supportLists]--><span><span>iii)<span> </span></span></span><!--[endif]--><span dir="ltr"><span>De manière complètement indépendante et asynchrone, le processus d’arrière plan CHECKPOINT écrit les pages de données et d’index modifiées (dirty pages) sur le disque, sans se préoccuper de savoir si elles appartiennent à une transaction validée ou non. </span></span></p>
<p class="MsoNormal"><span> </span></p>
<p class="MsoNormal"><span>A partir de là, deux situations peuvent se produire au point de crash: </span></p>
<p class="MsoNormal"><!--[if !supportLists]--><span> <span>1)<span> </span></span></span><!--[endif]--><span dir="ltr"><span>Une transaction peut être validée (committée) par l’utilisateur mais le CHECKPOINT n’a pas eu le temps d’écrire les pages de données / d’index sur disque. Il va falloir réécrire ces pages dans le fichier de données au redémarrage de l’instance (<strong>REDO </strong>ou ROLL-FORWARD). </span></span></p>
<p class="MsoNormal"><!--[if !supportLists]--><span><span>2)<span> </span></span></span><!--[endif]--><span dir="ltr"><span>Le CHECKPOINT qui n’a pas de vision sur l’état de la transaction peut avoir écrit ses pages sur disque avant qu’elle n’ait été validée par l’utilisateur. Auquel cas il faudra défaire les pages écrites car au point de crash car la transaction ne peut être considérée comme valide. (<strong>UNDO </strong>ou ROLLBACK). </span></span></p>
<p class="MsoNormal"><span> </span></p>
<p class="MsoNormal"><span>C’est la combinaison de ces deux actions que l’on appelle le <strong>RECOVERY</strong>. Ce processus intervient dans de nombreux changements d’état de la base, et notamment pour ce qui nous intéresse, lors de la phase de restauration d’une sauvegarde.</span></p>
<p class="MsoNormal"><span><span> </span> </span></p>
<p class="MsoNormal"><span>Lorsque le BACKUP DATABASE est exécuté, il commence par forcer l’exécution d’un CHECKPOINT dans la base concernée. Ce CHECKPOINT aura pour effet d’entériner des transactions validées depuis ma dernière sauvegarde de journal : Les pages de données / d’index sont écrites sur disque, la sauvegarde n’a donc plus besoin de s’en préoccuper. Bien sûr il peut aussi écrire les pages de données / d’index d’une transaction qui n’est pas encore validée. Immédiatement ensuite, il va relever un numéro de transaction (LSN pour Log Sequence Number)<span> </span>dans le journal pour s’en servir comme borne de départ pour le RECOVERY. Appelons-le <strong>LSN1</strong>. </span></p>
<p class="MsoNormal"><span> Puis il va lire et écrire les pages de données depuis le fichier MDF ou les différents filegroups, et les écrire dans le fichier de sauvegarde. Une fois terminées ces écritures, il renote le LSN courant (qui entre temps peut avoir<span> </span>évolué), et s’en sert comme borne de fin (<strong>LSN2</strong>). Puis il va sauvegarder tout ce qui se trouve entre (<strong>LSN2 – LSN1</strong>). Certaines transactions seront validées, certaines ne seront peut être pas terminées, mais peut importe, car au moment de la restauration, le processus de RECOVERY fera son œuvre pour ramener la base à un état transactionnel consistant. </span></p>
<p class="MsoNormal"><span> </span></p>
<p class="MsoNormal"><span>Si le LSN2 lui ne change pas car c’est toujours le dernier numéro généré dans le journal qui sera utilisé, le problème vient plus du calcul du LSN de départ car il va dépendre de la situation dans laquelle se trouve le BACKUP DATABASE au départ. <strong>Globalement, je peux me trouver dans deux cas :</strong></span></p>
<p class="MsoNormal"><span> </span></p>
<p class="MsoNormal"><!--[if !supportLists]--><span>-<span> </span></span><!--[endif]--><span dir="ltr"><strong><span>Soit il n’y a aucune transaction en cours au moment où commence la sauvegarde </span></strong></span><span>: auquel cas LSN1 sera égale à la valeur du LSN généré par le CHECKPOINT (lancé par le BACKUP):</span></p>
<p style="text-align: center;"><a href="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup1.png"><img class="size-medium wp-image-51 aligncenter" src="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup1-300x257.png" alt="hotbackup1" /></a></p>
<p class="MsoNormal"><span>L’effet du CHECKPOINT ici est de flusher les pages de données modifiées par T1, T2 et T3, pour ne pas à avoir à les prendre dans la sauvegarde du journal. Ces pages se retrouvent sur disque, et seront capturées lors de la copie de données. </span></p>
<p class="MsoNormal"><span> LSN2 est toujours le LSN courant capté dès la fin de la copie de données. Dans ce cas, T4 est terminée mais on est en plein milieu de T5, donc on prend quand même ce ‘fragment’ de T5. Lors de la restauration, T4 sera réappliquée et T5 sera rollbackée:</span></p>
<p class="MsoNormal" style="text-align: center;"><a href="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup5.png"><img class="aligncenter size-medium wp-image-52" src="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup5-300x117.png" alt="" /></a></p>
<p class="MsoNormal"><strong><span>Soit il y<span> </span>aura au moins une transaction en cours </span></strong><span>: auquel cas, SQL Server va aller rechercher le LSN de départ de la transaction active la plus ancienne. Dans l&#8217;exemple ci-dessous, il s&#8217;agit de T2:<br />
</span></p>
<p class="MsoNormal" style="text-align: center;"><a href="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup2.png"><img class="aligncenter size-medium wp-image-54" src="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup2-300x244.png" alt="" /> </a></p>
<p class="MsoNormal">
<p class="MsoNormal"><span>Dans ce cas, T2 et T4 qui sont terminées avant la fin de la copie de données seront réappliquées et T5 et T3 rollbackées:</span></p>
<p class="MsoNormal" style="text-align: center;"><a href="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup4.png"><img class="size-medium wp-image-56 aligncenter" src="https://www.alldb.fr/blog/wp-content/uploads/2008/12/hotbackup4-300x73.png" alt="" /></a></p>
<p class="MsoNormal">La table msdb.dbo.backupset qui stocke des données pour chaque sauvegarde effectuée permet de vérifier dans quel état se trouvait la base au moment de la sauvegarde. Pour le déterminer, il faut comparer les valeurs de checkpoint_lsn et first_lsn:</p>
<p class="MsoNormal"><strong>- checkpoint_lsn = first_lsn:</strong> alors il n&#8217;y avait pas de transaction en cours au moment du BACKUP DATABASE.</p>
<p class="MsoNormal">
<div>
<div class="O2">
<pre><span>select first_lsn, checkpoint_lsn, last_lsn from msdb.dbo.backupset where database_name<span>  </span>= ‘CAPDATA’
</span></pre>
</div>
<div class="O2">
<pre><span>first_lsn<span> </span><span>    </span>             checkpoint_lsn<span>       </span>      last_lsn
</span></pre>
</div>
<div class="O2">
<pre><span><em>--------------------       --------------------       --------------------
</em></span></pre>
</div>
<div class="O2">
<pre><span><em><strong>1341</strong> 0000000<strong>302</strong> 000<strong>51</strong><span>     </span><strong>1341</strong> 0000000<strong>302</strong> 000<strong>51</strong><span>       </span>1341 0000000323 00001</em><strong><em>
</em></strong></span></pre>
</div>
</div>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal"><strong>- first_lsn &lt; checkpoint_lsn:</strong> alors il y avait au moins une transaction en cours.</p>
<p class="MsoNormal">
<p class="MsoNormal">
<div class="O1">
<div>
<pre><span>select first_lsn, checkpoint_lsn, last_lsn from msdb.dbo.backupset where database_name<span>  </span>= ‘CAPDATA’
</span><span>
first_lsn<span> </span><span>               </span>checkpoint_lsn<span>          </span>last_lsn
</span></pre>
</div>
<div>
<pre><span><em>--------------------     ---------------         --------------------
</em></span></pre>
</div>
<div>
<pre><strong><span><em>1341</em></span></strong><span><em> 0000000</em></span><strong><span><em>510</em></span></strong><span><em> 000</em></span><strong><span><em>2</em></span></strong><span><em><span>     </span><strong>1341 </strong>0000000<strong>523</strong> 000<strong>98</strong><span>    </span>1341 0000000563 00001</em></span></pre>
</div>
</div>
<div class="O1">[ David B.]</div>
<p> <script type="text/javascript" src="http://tcr.tynt.com/javascripts/Tracer.js?user=d4FlbGI04r35lZadbi-bpO"></script><br />
<strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/une-alternative-a-xp_fixeddrives/" rel="bookmark" title="17 août 2010">Une alternative à xp_fixeddrives</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/sybase-ase-planification-dans-adaptive-server/" rel="bookmark" title="19 juin 2009">Planification dans Adaptive Server</a> (David BAFFALEUF) [Sybase]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-d%e2%80%99une-physical-standby-database/" rel="bookmark" title="8 mars 2010">Création d’un Dataguard physique</a> (Guillaume DEFENDINI) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 4.022 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%2Fsql-server-principes-dune-sauvegarde-a-chaud%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fsql-server-principes-dune-sauvegarde-a-chaud%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/weK0hjIbcTI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/sql-server-principes-dune-sauvegarde-a-chaud/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/sql-server-principes-dune-sauvegarde-a-chaud/</feedburner:origLink></item>
		<item>
		<title>Modes de récupération et journal de transactions, épisode 2</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/T8XFlLJHl2U/</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/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/modes-de-recuperation-et-journal-de-transactions-episode-1/" rel="bookmark" title="13 juin 2008">Modes de récupération et journal de transactions, épisode 1</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/" rel="bookmark" title="23 avril 2010">Jeux de caractères, Unicode  et Base de données</a> (Guillaume DEFENDINI) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 3.976 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" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/T8XFlLJHl2U" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-2/</feedburner:origLink></item>
		<item>
		<title>Modes de récupération et journal de transactions, épisode 1</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/jydHVPNgyeY/</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/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/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/modes-de-recuperation-et-journal-de-transactions-episode-2/" rel="bookmark" title="11 décembre 2008">Modes de récupération et journal de transactions, épisode 2</a> (David BAFFALEUF) [SQL Server]</li>
<li><a href="http://blog.capdata.fr/index.php/jeux-de-caracteres-unicode-et-base-de-donnees/" rel="bookmark" title="23 avril 2010">Jeux de caractères, Unicode  et Base de données</a> (Guillaume DEFENDINI) [GénéralMySQLOracleSQL ServerSybase]</li>
<li><a href="http://blog.capdata.fr/index.php/oracle-les-rpms-et-les-dependances-avec-yum/" rel="bookmark" title="6 novembre 2009">Oracle, les Rpms plus de souci avec YUM</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 4.021 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" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/jydHVPNgyeY" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://blog.capdata.fr/index.php/modes-de-recuperation-et-journal-de-transactions-episode-1/</feedburner:origLink></item>
		<item>
		<title>Se connecter à SQL Server à travers Oracle, quelle drôle d’idée ?</title>
		<link>http://feedproxy.google.com/~r/CapDataTeamBlog/~3/DvtPqEUUUz8/</link>
		<comments>http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 09:46:20 +0000</pubDate>
		<dc:creator>Thierry GASCARD</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[sql server oracle gateway ole db]]></category>

		<guid isPermaLink="false">http://192.168.1.220:8080/blogs/oracle/?p=6</guid>
		<description><![CDATA[Cet article est écrit par Thierry GASCARD.
La première solution est d&#8217;utiliser la &#8220;gateway Oracle pour SQL SERVER &#8221; (15000$ par serveur).
La deuxième gratuite est d&#8217;utiliser OLE DB.
Je vais m&#8217;intéresser à la deuxième solution, vous en devinez la raison  
1) créer un fichier UDL (vide puis ajouter l&#8217;extension .udl) sous C:\\Documents and Settings\\thierry\\Bureau\\client1.udl, puis double [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est écrit par <a href="mailto:tgascard@capdata.fr" target="_blank">Thierry GASCARD.</a></p>
<p>La première solution est d&#8217;utiliser la &#8220;gateway Oracle pour SQL SERVER &#8221; (15000$ par serveur).</p>
<p>La deuxième gratuite est d&#8217;utiliser OLE DB.</p>
<p>Je vais m&#8217;intéresser à la deuxième solution, vous en devinez la raison <img src='http://blog.capdata.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>1) créer un fichier UDL (vide puis ajouter l&#8217;extension .udl) sous C:\\Documents and Settings\\thierry\\Bureau\\client1.udl, puis double cliquer</p>
<p>-onglet Fournisseur : choisir le fournisseur &#8220;Microsoft OLE DB Provider for SQL Server&#8221;</p>
<p>s&#8217;il n&#8217;est pas présent  téléchargez <a title="MDAC 2.8" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=6c050fe3-c795-4b7d-b037-185d0506396c&amp;displaylang=en" target="_blank">MDAC </a>(merci david)<br />
-onglet connexion : nom du serveur SQL (minsk\aquarium), utilisateur/mot de passe, base de données client1<br />
2) sous $ORACLE_HOME\hs\admin<br />
faire une copie du fichier inithsoledb.ora en initclient1.ora<br />
3) configuer initclient1.ora<br />
HS_FDS_CONNECT_INFO =&#8221;UDLFILE=C:\\Documents and Settings\\thierry\\Bureau\\client1.udl&#8221;<br />
HS_FDS_TRACE_LEVEL = 0<br />
HS_FDS_TRACE_FILE_NAME = client1.trc</p>
<p>attention doubler \ (merci manu..)<br />
4) configuer le fichier tnsnames.ora<br />
CLIENT1  =<br />
(DESCRIPTION=<br />
(ADDRESS=(PROTOCOL=tcp)(HOST=pc-thierry)(PORT=1524))<br />
(CONNECT_DATA=(SID=CLIENT1))<br />
(HS=OK)<br />
)<br />
5) configurer le fichier listener.ora<br />
ajouter aux services de votre listener<br />
(SID_DESC=<br />
(SID_NAME=CLIENT1)<br />
(ORACLE_HOME = D:\app\oracle\10.2.0\db_1)<br />
(PROGRAM=hsolesql)<br />
)<br />
6) créer le database link<br />
CREATE PUBLIC DATABASE LINK &#8220;CLIENT1&#8243; USING &#8216;CLIENT1&#8242;;</p>
<p>7) tester la connexion<br />
select * from sysobjects@client1;</p>
<p><em>remarque : en cas de souci, vous pouvez poser une trace.<br />
mettre le paramètre HS_FDS_TRACE_LEVEL = 4<br />
la trace se trouvera sous D:\app\oracle\10.2.0\db_1\hs\trace</em><strong>Continuez votre lecture sur le blog :</strong>
<ul class="similar-posts">
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-11gr2-64-bits-sur-red-hat-5-partie-1/" rel="bookmark" title="3 mars 2010">Installation Oracle 11gR2 64 bits sur Red Hat 5 Partie 1</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-oracle-64-bits-sur-red-hat-5/" rel="bookmark" title="5 juin 2009">Installation Oracle 64 bits sur Red Hat 5</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/creation-et-utilisation-docfs2/" rel="bookmark" title="5 juin 2009">Création et utilisation d&#8217;OCFS2</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/installation-asm-sur-suse-10-en-64-bits-avec-multipathing-emc-powerpath/" rel="bookmark" title="5 juin 2009">Installation ASM sur SUSE 10 en 64 Bits avec multipathing (EMC Powerpath)</a> (Thierry GASCARD) [Oracle]</li>
<li><a href="http://blog.capdata.fr/index.php/utiliser-asmcmd/" rel="bookmark" title="5 juin 2009">Utiliser ASMCMD</a> (Thierry GASCARD) [Oracle]</li>
</ul>
<p><!-- Similar Posts took 3.934 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%2Fse-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fse-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<img src="http://feeds.feedburner.com/~r/CapDataTeamBlog/~4/DvtPqEUUUz8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.capdata.fr/index.php/se-connecter-a-sql-server-a-travers-oracle-quelle-drale-didae/</feedburner:origLink></item>
	</channel>
</rss>
