N’utilisez pas les paramètres par défaut AUTOGROW!

Mis en avant

Au cours de mes audits clients, j’ai souvent vu les paramètres d’expansion de fichiers par défaut sur les bases de données utilisateurs et comme vous le savez ceci n’est pas forcément une bonne pratique. Laissez moi vous raconter une histoire drôle vécue qui concerne une situation extrême avec un fichier journal et ses paramètres par défaut.

> Pour lire la suite (en anglais)

David Barbarin
MVP & MCM SQL Server

Utilisation des snapshots VSS et SQL Server – Part I

Mis en avant

Ceci est probablement une série de billets concernant les snapshots VSS et SQL Server. Laissez moi introduire le sujet avec cette anecdote:

Il y a quelques temps, nous avons implémenté une stratégie de sauvegarde chez un de mes clients basée sur une combinaison FULL, DIFF et sauvegarde du journal des transactions. Aucun problème pendant un moment et un jour mon client m’appelle en me disant que depuis un certain temps, la sauvegarde différentielle en place ne se faisait plus correctement avec le message d’erreur suivant ..

> Lire la suite (en anglais)

David Barbarin
MVP & MCM SQL Server

Quand tempdb peut être à l’origine de problèmes indirects

Mis en avant

Il y a quelques semaines, j’ai discuté d’un cas intéressant avec un de mes amis qui a fait face à un problème étrange (en surface) avec une instance SQL Server qui a manqué de threads de travail. Je ne peux malheureusement pas dévoiler le vrai contexte client ici mais j’ai décidé de reproduire le même problème afin de partager avec vous certaines informations intéressantes. La prochaine partie de ce blog se réfère uniquement à mes propres tests qui représentent dans sa plus grande partie le problème cité ci-dessus.

> Lire la suite (en anglais)

David Barbarin
MVP & MCM SQL Server

S’aventurer dans l’insertion en masse d’un fichier d’erreur SQL Server et l’ordre des données

Mis en avant

N’avez-vous jamais tenté une insertion en masse d’un fichier d’erreur SQL Server pour en extraire les informations utiles dans un rapport par exemple?
Si tel est le cas, vous vous êtes probablement demandé comment garder l’ordre du fichier dans une requête sans avoir une colonne de référence pour l’ordre des données. Il existe bien entendu des solutions mais ce n’est pas le but de ce billet. A la place, je voudrais partager avec vous une discussion intéressante sur le forum developpez.com concernant l’assurance d’obtenir l’ordre les données dans un fichier d’erreur SQL Server avec une simple requête SELECT sans spécifier la clause ORDER BY.

> Lire la suite (en anglais)

David Barbarin
MVP & MCM SQL Server

Analyser facilement un rapport de processus bloqués

Mis en avant

Quel DBA n’a jamais eu à faire face à un problème de performance provoqué par des blocage de plusieurs processus? En réalité, je suis sûr que non. Résoudre un problème de blocage de processus n’est pas toujours simple et peut exiger d’utiliser des outils qui simplifieront cette tâche. Il y a quelques mois, j’ai eu à gérer un tel scénario chez un de mes clients avec une cascade de processus bloqués dans une période donnée.

> Lire la suite (en anglais)

David Barbarin
MVP & MCM SQL Server

Considérations sur le placement de fichiers des bases de données SQL Server avec Netapp et SnapManager

Mis en avant

Lorsqu’on installe SQL Server, on a bien sûr à considérer comment placer les fichiers de bases de données. A ce stade, il est probable que vous suivrez les bonnes pratiques bien connues ou les guidelines fournis pour Microsoft mais êtes vous réellement au courant de ceux fournis par les vendeurs de stockage? Parlons en dans ce billet.

> Lire la suite (en anglais)

David Barbarin
MVP & MCM SQL Server

SQL Saturday à Paris 2013 le 14 septembre 2013 – Rappel

Mis en avant

Il est temps de dévoiler un peu le contenu de la session que je présenterai au cours des SQL Saturdays et de faire par la même occasion une piqure de rappel Sourire

Je pense que le titre de la session est assez parlante : SQL Trace vs Extended Events … Les évènements étendues sont devenus avec SQL Server 2012 un outil de diagnostic extrêmement puissant mais pourtant je pourrais parier que la majorité des développeurs ou des DBA utilisent encore le profiler de SQL Serve car ce dernier reste encore très pratique à utiliser. Pourtant les possibilités du profiler sont loin d’égaler celles offertes par les évènements étendues et ce c’est que je tenterai de montrer lors de cette session.

Les sessions sont les évènements étendues ne sont pas nouvelles. David Baffaleuf ou encore Nicolas Souquet en ont parlé avant moi et le but ne sera pas de faire doublon avec leur excellent travail. La grande majorité de la session sera donc dédiée à une présentation concrète de cas pratique où les évènements étendues auront un grand intérêt !

En espérant vous voir nombreux Sourire

N’oublions les autres sessions très intéressantes présentées par Christophe Laporte avec IO Fusion ou encore celle présentée par Hugo Kornelis sur les index columstore pour la partie DBA … que du bonheur !

 

SQLSAT251_web_thumb1

 

David BARBARIN (Mikedavem)
MVP SQL Server

Gérer les erreurs générées par la commande DBCC CHECKDB dans un script T-SQL

Mis en avant

La vérification d’intégrité des bases de données s’effectue par la commande DBCC CHECKDB. Le résultat de cette commande est assez verbeuse par défaut et peut poser problème lorsque la vérification d’intégrité est  utilisé dans des scripts T-SQL personnalisés de maintenance par exemple.

 

Posons un peu le contexte et le pourquoi de ce billet. En réalité j’ai eu l’occasion de travailler (comme beaucoup je pense) sur la création de plans de maintenance "custom". L’idée a été de construire un jeu de script permettant de pouvoir gérer l’ensemble des tâches que l’on peut avoir à utiliser pour la maintenance des bases de données. Une de ces tâches concerne la vérification d’intégrité des bases. Cette vérification se fait à l’aide de la commande bien connue DBCC CHECKDB. Dans notre contexte l’idée est de pouvoir exécuter une tâche de maintenance et d’enregistrer dans une table de log les données suivantes :

  • Nom de la tâche
  • Nom de la base concernée
  • Durée de la tâche
  • Statut de la tâche (OK ou en échec)
  • Envoi par mail des tâches en échec à posteriori avec le détail de l’erreur

Ceci nous permet d’avoir une traçabilité des tâches de maintenance par la suite et pouvoir les consommer à des fins d’analyse.

Lorsque l’on scripte une vérification d’intégrité à l’aide de la commande DBCC CHECKDB on s’aperçoit rapidement que la gestion des erreurs liées à cette commande n’est pas triviale. C’est que nous verrons dans le cadre de ce billet.

 

icon_arrow Une sortie verbeuse

Voici la sortie d’une commande DBCC CHECKDB sur une base de données corrompue :

DBCC CHECKDB ('DemoCorruptMetadata')

DBCC results for ‘DemoCorruptMetadata’.
Service Broker Msg 9675, State 1: Message Types analyzed: 14.
Service Broker Msg 9676, State 1: Service Contracts analyzed: 6.
Service Broker Msg 9667, State 1: Services analyzed: 3.
Service Broker Msg 9668, State 1: Service Queues analyzed: 3.
Service Broker Msg 9669, State 1: Conversation Endpoints analyzed: 0.
Service Broker Msg 9674, State 1: Conversation Groups analyzed: 0.
Service Broker Msg 9670, State 1: Remote Service Bindings analyzed: 0.
Service Broker Msg 9605, State 1: Conversation Priorities analyzed: 0.
Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3853, State 1: Attribute (object_id=1977058079) of row (object_id=1977058079,column_id=1) in sys.columns does not have a matching row (object_id=1977058079) in sys.objects.
Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3853, State 1: Attribute (object_id=1977058079) of row (object_id=1977058079,column_id=2) in sys.columns does not have a matching row (object_id=1977058079) in sys.objects.
CHECKDB found 0 allocation errors and 2 consistency errors not associated with any single object.
DBCC results for ‘sys.sysrscols’.
There are 872 rows in 9 pages for object "sys.sysrscols".
DBCC results for ‘sys.sysrowsets’.
There are 124 rows in 1 pages for object "sys.sysrowsets".
DBCC results for ‘sys.sysclones’.
There are 0 rows in 0 pages for object "sys.sysclones".
DBCC results for ‘sys.sysallocunits’.
There are 138 rows in 2 pages for object "sys.sysallocunits".
DBCC results for ‘sys.sysfiles1′.
There are 2 rows in 1 pages for object "sys.sysfiles1".
DBCC results for ‘sys.sysseobjvalues’.
There are 0 rows in 0 pages for object "sys.sysseobjvalues".
DBCC results for ‘sys.syspriorities’.
There are 0 rows in 0 pages for object "sys.syspriorities".
DBCC results for ‘sys.sysdbfrag’.
There are 0 rows in 0 pages for object "sys.sysdbfrag".
DBCC results for ‘sys.sysfgfrag’.
There are 0 rows in 1 pages for object "sys.sysfgfrag".
DBCC results for ‘sys.sysdbfiles’.
There are 2 rows in 1 pages for object "sys.sysdbfiles".
DBCC results for ‘sys.syspru’.
There are 0 rows in 0 pages for object "sys.syspru".
DBCC results for ‘sys.sysbrickfiles’.
There are 0 rows in 0 pages for object "sys.sysbrickfiles".
DBCC results for ‘sys.sysphfg’.
There are 1 rows in 1 pages for object "sys.sysphfg".
DBCC results for ‘sys.sysprufiles’.
There are 2 rows in 1 pages for object "sys.sysprufiles".
DBCC results for ‘sys.sysftinds’.
There are 0 rows in 0 pages for object "sys.sysftinds".
DBCC results for ‘sys.sysowners’.
There are 14 rows in 1 pages for object "sys.sysowners".
DBCC results for ‘sys.sysdbreg’.
There are 0 rows in 0 pages for object "sys.sysdbreg".
DBCC results for ‘sys.sysprivs’.
There are 136 rows in 1 pages for object "sys.sysprivs".
DBCC results for ‘sys.sysschobjs’.
There are 2180 rows in 29 pages for object "sys.sysschobjs".
DBCC results for ‘sys.syscolpars’.
There are 698 rows in 11 pages for object "sys.syscolpars".
DBCC results for ‘sys.sysxlgns’.
There are 0 rows in 0 pages for object "sys.sysxlgns".
DBCC results for ‘sys.sysxsrvs’.
There are 0 rows in 0 pages for object "sys.sysxsrvs".
DBCC results for ‘sys.sysnsobjs’.
There are 1 rows in 1 pages for object "sys.sysnsobjs".
DBCC results for ‘sys.sysusermsgs’.
There are 0 rows in 0 pages for object "sys.sysusermsgs".
DBCC results for ‘sys.syscerts’.
There are 0 rows in 0 pages for object "sys.syscerts".
DBCC results for ‘sys.sysrmtlgns’.
There are 0 rows in 0 pages for object "sys.sysrmtlgns".
DBCC results for ‘sys.syslnklgns’.
There are 0 rows in 0 pages for object "sys.syslnklgns".
DBCC results for ‘sys.sysxprops’.
There are 0 rows in 0 pages for object "sys.sysxprops".
DBCC results for ‘sys.sysscalartypes’.
There are 34 rows in 1 pages for object "sys.sysscalartypes".
DBCC results for ‘sys.systypedsubobjs’.
There are 0 rows in 0 pages for object "sys.systypedsubobjs".
DBCC results for ‘sys.sysidxstats’.
There are 130 rows in 1 pages for object "sys.sysidxstats".
DBCC results for ‘sys.sysiscols’.
There are 317 rows in 3 pages for object "sys.sysiscols".
DBCC results for ‘sys.sysendpts’.
There are 0 rows in 0 pages for object "sys.sysendpts".
DBCC results for ‘sys.syswebmethods’.
There are 0 rows in 0 pages for object "sys.syswebmethods".
DBCC results for ‘sys.sysbinobjs’.
There are 23 rows in 1 pages for object "sys.sysbinobjs".
DBCC results for ‘sys.sysaudacts’.
There are 0 rows in 0 pages for object "sys.sysaudacts".
DBCC results for ‘sys.sysobjvalues’.
There are 134 rows in 13 pages for object "sys.sysobjvalues".
DBCC results for ‘sys.syscscolsegments’.
There are 0 rows in 0 pages for object "sys.syscscolsegments".
DBCC results for ‘sys.syscsdictionaries’.
There are 0 rows in 0 pages for object "sys.syscsdictionaries".
DBCC results for ‘sys.sysclsobjs’.
There are 16 rows in 1 pages for object "sys.sysclsobjs".
DBCC results for ‘sys.sysrowsetrefs’.
There are 0 rows in 0 pages for object "sys.sysrowsetrefs".
DBCC results for ‘sys.sysremsvcbinds’.
There are 0 rows in 0 pages for object "sys.sysremsvcbinds".
DBCC results for ‘sys.sysxmitqueue’.
There are 0 rows in 0 pages for object "sys.sysxmitqueue".
DBCC results for ‘sys.sysrts’.
There are 1 rows in 1 pages for object "sys.sysrts".
DBCC results for ‘sys.sysconvgroup’.
There are 0 rows in 0 pages for object "sys.sysconvgroup".
DBCC results for ‘sys.sysdesend’.
There are 0 rows in 0 pages for object "sys.sysdesend".
DBCC results for ‘sys.sysdercv’.
There are 0 rows in 0 pages for object "sys.sysdercv".
DBCC results for ‘sys.syssingleobjrefs’.
There are 156 rows in 1 pages for object "sys.syssingleobjrefs".
DBCC results for ‘sys.sysmultiobjrefs’.
There are 107 rows in 1 pages for object "sys.sysmultiobjrefs".
DBCC results for ‘sys.sysguidrefs’.
There are 0 rows in 0 pages for object "sys.sysguidrefs".
DBCC results for ‘sys.sysfoqueues’.
There are 0 rows in 0 pages for object "sys.sysfoqueues".
DBCC results for ‘sys.syschildinsts’.
There are 0 rows in 0 pages for object "sys.syschildinsts".
DBCC results for ‘sys.syscompfragments’.
There are 0 rows in 0 pages for object "sys.syscompfragments".
DBCC results for ‘sys.sysftsemanticsdb’.
There are 0 rows in 0 pages for object "sys.sysftsemanticsdb".
DBCC results for ‘sys.sysftstops’.
There are 0 rows in 0 pages for object "sys.sysftstops".
DBCC results for ‘sys.sysftproperties’.
There are 0 rows in 0 pages for object "sys.sysftproperties".
DBCC results for ‘sys.sysxmitbody’.
There are 0 rows in 0 pages for object "sys.sysxmitbody".
DBCC results for ‘sys.sysfos’.
There are 0 rows in 0 pages for object "sys.sysfos".
DBCC results for ‘sys.sysqnames’.
There are 100 rows in 1 pages for object "sys.sysqnames".
DBCC results for ‘sys.sysxmlcomponent’.
There are 100 rows in 1 pages for object "sys.sysxmlcomponent".
DBCC results for ‘sys.sysxmlfacet’.
There are 112 rows in 1 pages for object "sys.sysxmlfacet".
DBCC results for ‘sys.sysxmlplacement’.
There are 19 rows in 1 pages for object "sys.sysxmlplacement".
DBCC results for ‘sys.sysobjkeycrypts’.
There are 0 rows in 0 pages for object "sys.sysobjkeycrypts".
DBCC results for ‘sys.sysasymkeys’.
There are 0 rows in 0 pages for object "sys.sysasymkeys".
DBCC results for ‘sys.syssqlguides’.
There are 0 rows in 0 pages for object "sys.syssqlguides".
DBCC results for ‘sys.sysbinsubobjs’.
There are 3 rows in 1 pages for object "sys.sysbinsubobjs".
DBCC results for ‘sys.syssoftobjrefs’.
There are 0 rows in 0 pages for object "sys.syssoftobjrefs".
DBCC results for ‘sys.queue_messages_1993058136′.
There are 0 rows in 0 pages for object "sys.queue_messages_1993058136".
DBCC results for ‘sys.queue_messages_2025058250′.
There are 0 rows in 0 pages for object "sys.queue_messages_2025058250".
DBCC results for ‘sys.queue_messages_2057058364′.
There are 0 rows in 0 pages for object "sys.queue_messages_2057058364".
DBCC results for ‘sys.filestream_tombstone_2089058478′.
There are 0 rows in 0 pages for object "sys.filestream_tombstone_2089058478".
DBCC results for ‘sys.syscommittab’.
There are 0 rows in 0 pages for object "sys.syscommittab".
DBCC results for ‘sys.filetable_updates_2121058592′.
There are 0 rows in 0 pages for object "sys.filetable_updates_2121058592".
CHECKDB found 0 allocation errors and 2 consistency errors in database ‘DemoCorruptMetadata’.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

 

On se rend vite compte que la quantité d’information qui nous intéresse ici reste négligeable par rapport à la quantité totale d’information produite en sortie par notre commande. Ici la commande DBCC CHECKDB a produit 162 lignes d’information alors que  moins de 10 lignes nous intéresse ici. Heureusement pour nous, nous pouvons jouer avec les options NO_INFOMSGS et ALL_ERRORMSGS pour limiter le nombre d’informations produites par DBCC CHECKDB. Pour rappel NO_INFOMSGS permet d’éliminer les messages d’information produites en sortie et ALL_ERRORMSGS permet d’afficher toutes les erreurs rencontrées lors d’une opération de vérification de bases de données. Par défaut seulement les 1000 premiers messages d’erreur sont affichés depuis SQL Server Management Studio.

 

icon_arrow Utilisation des options NO_INFOMSGS, ALL_ERRORMSGS

DBCC CHECKDB ('DemoCorruptMetadata') WITH NO_INFOMSGS, ALL_ERRORMSGS

 

Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3853, State 1: Attribute (object_id=1977058079) of row (object_id=1977058079,column_id=1) in sys.columns does not have a matching row (object_id=1977058079) in sys.objects.
Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3853, State 1: Attribute (object_id=1977058079) of row (object_id=1977058079,column_id=2) in sys.columns does not have a matching row (object_id=1977058079) in sys.objects.
CHECKDB found 0 allocation errors and 2 consistency errors not associated with any single object.
CHECKDB found 0 allocation errors and 2 consistency errors in database ‘DemoCorruptMetadata’.

 

On a ici bien réduit le nombre de lignes produites par notre commande DBCC CHECKDB avec l’affichage du détail des erreurs rencontrées et 2 messages d’information qui ne sont ni plus ni moins qu’un récapitulatif de ces erreurs.

 

icon_arrow Gestion de la sortie de la commande DBCC CHECKDB dans un script T-SQL

Après avoir limité le nombre d’information utiles comment nous en servir pour construire une logique de maintenance par script ? L’idée ici est simplement de pouvoir détecter un problème d’intégrité et de prévenir les personnes concernées (notamment l’équipe DBA) qu’un problème est survenu à ce moment là

A priori 2 voies d’exploitation évidentes peuvent être prises en compte :

  • On peut utiliser la variable @@ERROR et vérifier que celle-ci soit différente de 0
  • On peut utiliser les blocs de gestions d’erreur TRY CATCH

 

Avec la variable @@ERROR :

dbcc checkdb('DemoCorruptMetadata') WITH no_infomsgs, all_errormsgs;
IF @@ERROR  <>0    
BEGIN    
 print '';    
 print '--> error during dbcc checkdb';    
END

 

Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3853, State 1: Attribute (object_id=1977058079) of row (object_id=1977058079,column_id=1) in sys.columns does not have a matching row (object_id=1977058079) in sys.objects.
Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3853, State 1: Attribute (object_id=1977058079) of row (object_id=1977058079,column_id=2) in sys.columns does not have a matching row (object_id=1977058079) in sys.objects.
CHECKDB found 0 allocation errors and 2 consistency errors not associated with any single object.
CHECKDB found 0 allocation errors and 2 consistency errors in database ‘DemoCorruptMetadata’.
 
–> error during dbcc checkdb

 

La variable @@ERROR nous permet effectivement de pouvoir détecter les erreurs engendrées par la commande DBCC CHECKDB. Il suffit ensuite de coder la logique de maintenance qui nous intéresse. Cependant si on utilise notre script T-SQL dans un job SQL Server, les erreurs produites impliqueront une étape de job en échec. La question est donc de savoir ce résultat est attendu ou non ? Effectivement ce n’est pas parce qu’une commande DBCC CHECKDB produit une erreur qu’un job SQL Server doit forcément partir en échec. En réalité tout dépendra de la logique d’exécution globale concernée par ce script. On peut tout à fait traiter l’erreur de job et effectuer une surveillance sur l’état de ce job par envoi d’alerte ou via des outils tiers par exemple. On peut aussi vouloir enregistrer l’erreur sans que le job parte en échec, avec l’exécution d’étapes supplémentaires sans pour autant avoir une logique d’exécution complexe du style "si étape 1 échec –> aller à l’étape 3 sinon aller à l’étape 2 etc … A mon humble avis les jobs SQL Server ne sont pas vraiment désignés pour gérer des logiques complexes de workflow . Dans le cadre de notre script nous avons retenu une solution générique et simple : si une tâche génère une erreur alors celle-ci est enregistrée dans une table de log et l’information pourra être envoyé à posteriori par email. Le choix est laissé à l’utilisateur final. 

 

Avec le bloc de gestion d’erreur BEGIN TRY, CATCH :

BEGIN try    
 dbcc checkdb('DemoCorruptMetadata') WITH no_infomsgs, all_errormsgs;    
END try    
BEGIN catch    
 print '--> error during dbcc checkdb';    
END catch

 

CHECKDB found 0 allocation errors and 2 consistency errors not associated with any single object.
CHECKDB found 0 allocation errors and 2 consistency errors in database ‘DemoCorruptMetadata’.

 

Comme on peut le remarquer le bloc de gestion TRY , CATCH ne va malheureusement pas nous être d’une grande utilité ici car les dernières lignes d’information produites par la commande DBCC CHECKDB empêchent notre bloc de gestion d’erreur de détecter les erreurs produites par notre commande DBCC CHECKDB quelques lignes plus haut.

 

Avons nous une autre alternative dans ce cas ? La réponse est oui. Il est également possible d’enregistrer les erreurs produites lors d’une vérification d’intégrité dans une table SQL en utilisant l’option TABLERESULTS de cette manière :

 

icon_arrow Utilisation de l’option TABLERESULTS

 

DBCC CHECKDB('DemoCorruptMetadata')
WITH NO_INFOMSGS, ALL_ERRORMSGS, TABLERESULTS

 

dbcc_checkdb_tableresults

 

Il suffit ici d’extraire les informations produites dans la table et de gérer sa propre logique de maintenance. Dans mon cas je remplis une variable de table avec le résultat de la commande DBCC CHECKDB et l’option TABLERESULETS et je vérifie qu’au moins une ligne existe pour détecter la présence d’une erreur (la commande DBCC CHECKDB ne produit aucune ligne d’erreur si aucun problème d’intégrité n’est détecté).  L’information est ensuite enregistrée dans une table de log avec le numéro d’erreur et sera envoyé par mail à postériori.

 

L’option TABLERESULTS est-elle là solution miracle ? Malheureusement non car la commande DBCC CHECKDB peut produire certaines erreurs propres à son exécution et qui stopper franchement le script en cours d’exécution. C’est le cas de certaines erreurs sévères rencontrés par la commande DBCC CHECKDB.

 

icon_arrow Gestion des erreurs liées à l’exécution même de la commande DBCC CHECKDB

Voici quelques cas où l’exécution de la commande DBCC CHECKDB provoquera une erreur grave et un arrêt net du script T-SQL en cours d’exécution.

 

- Après avoir corrompu la page PFS (page id = 1)  à l’aide d’un éditeur hexadécimal de ma base DemoCorruptMetada le script SQL se stoppera net avec le message d’erreur suivant :

Msg 0, Level 11, State 0, Line 0
A severe error occured on the current command. The results, if any, should be discarded

 

- De la même manière Après avoir supprimer une ligne dans la table système sys.syscolpars en redémarrant l’instance SQL Server en mode mono utilisateur et se connectant en mode administrateur dédié la commande DBCC CHECKDB génère le message suivant :

 

Msg 0, Level 20, State 0, Line 0
A severe error occured on the current command. The results, if any, should be discarded

 

Pour une description des niveaux d’erreurs voir la documentation en ligne SQL Server (section "Understanding DBCC errors messages"). Dans ce cas il faudra effectivement gérer l’erreur de manière différente. Dans mon cas au début de chaque tâche une ligne est enregistrée dans une table de log. Si le script T-SQL est arrêté a date de fin de la tâche ne sera pas renseigné. Un email est envoyé pour les cas suivants :

  • Le statut de la tâche est égale à false
  • Le statut de la tâche est inconnu ou la date de fin d’une tâche n’est pas renseignée

 

Bonne gestion d’erreur !!

David BARBARIN (Mikedavem)
MVP SQL Server

SET TRANSACTION ISOLATION LEVEL READ COMMITTED et NOLOCK = pas de verrous ?

Mis en avant

Chez un de mes clients on est venu me dire la chose suivante : visiblement lorsque j’utilise le hint NOLOCK ou un niveau de transaction READ UNCOMMITED lorsque j’exécute une requête je vois quand même des verrous posés sur mes tables alors que je croyais le contraire et du coup ma requête en lecture doit bloquer les mises à jour … A cela j’ai répondu : la vérité est ailleurs Sourire

Plus sérieusement, la bonne question à se poser est la suivante : est-ce que le fait d’utiliser un hint NOLOCK ou un niveau de transaction permettant la lecture sale veut dire que aucun verrou n’est posé ?

 

Pour répondre prenons un exemple simple avec une requête dans la base de données AdventureWorksDW2012 :

SELECT *  
FROM dbo.FactInternetSales AS f  
CROSS JOIN dbo.FactInternetSales AS f2

 

Voyons les verrous posées par cette requête à l’aide de la DMV sys.dm_tran_locks :

SELECT  
 resource_database_id,    
 resource_type,  
 resource_subtype,    
 request_mode,  
 request_type,    
 request_status,    
 request_owner_type    
FROM sys.dm_tran_locks    
WHERE request_session_id = "session"

 

icon_arrow Avec un niveau d’isolation de transaction en read committed (niveau d’isolation par défaut) :

image

 

icon_arrow  Avec un niveau d’isolation de transaction en read uncommitted :

image

 

On voit d’abord que le niveau d’isolation de transaction en mode read uncommitted ne veut pas dire qu’il n’existe plus de verrou. Le 1er verrou (de type SHARED_TRANSACTION_WORKSPACE) nous intéresse moins ici car c’est un verrou posé lorsqu’il existe une connexion sur une base de données (en l’occurence database_id = 6 ici). Cela permet de protéger la base de données contre les suppressions accidentelles par exemple lorsqu’il existe une connexion sur cette dernière.

Les verrous suivants sont plus intéressants dans notre cas. On voit que la différence notoire est qu’il existe des verrous de type IS et type S dans un cas (read committed) et plus de verrou de ce type dans l’autre cas  (read uncommitted). Le niveau d’isolation de transaction par défaut utilisé par SQL Server garantit une lecture propre des données c’est la raison pour laquelle il existe des verrous de type S et IS à différents niveaux (OBJECT et PAGE) . Avec le niveau d’isolation permettant de la lecture sale ces verrous n’existent évidemment plus mais d’autres verrous existent cependant comme celui que l’on voit dans la dernière image : verrou de type Sch-S. Ce verrou protège la table contre les modifications pendant qu’une lecture est effectuée même si celle-ci n’est pas propre.

 

Faisons le même test avec une table HEAP (sans index cluster) avec la requête suivante :

SELECT *  
FROM dbo.DatabaseLog AS f    
CROSS JOIN dbo.DatabaseLog AS f2

 

… et voyons les verrous posées :

icon_arrow Avec un niveau d’isolation de transaction en read committed (niveau d’isolation par défaut) :

image

 

icon_arrow  Avec un niveau d’isolation de transaction en read uncommitted :

image

 

La aussi on peut voir qu’avec les verrous de type S ne sont plus présents sur les objets de type PAGE ou OBJET avec un niveau d’isolation de transaction en read uncommitted.  On a néanmoins un type de verrou supplémentaire que l’on n’avait pas  avec une table possédant un index cluster à la ligne 2 (resource_type = HOBT et resource_subtype = BULK_OPERATION). Ce type de verrou n’est présent que sur les tables HEAP pour protéger les lectures contre les pages potentiellement mal formatés via des opérations BULK (merci à Paul Randal pour la précision).

 

On vient donc de voir que la lecture sale sur SQL Server engendrait certains types de verrous. Cependant on peut pousser le raisonnement plus loin. Qui dit verrou veut dire aussi latch pour accéder aux structures physiques en mémoire … on peut essayer de voir si une requête avec un niveau d’isolation en read uncommitted produit des latchs. Pour cela on peut utiliser la DMV sys.dm_os_waiting_tasks comme ceci :

-- Création à la volée d'une table temporaire pour les tâches en attente    
SELECT TOP 1 *  
INTO #waiting_tasks    
FROM sys.dm_os_waiting_tasks;    
GO

-- On vide la table avant le test  
TRUNCATE TABLE #waiting_tasks;    
GO

-- Récupération des tâches en attente générées par la requête de test    
WHILE 1 = 1    
BEGIN    
 INSERT #waiting_tasks    
 SELECT *    
 FROM sys.dm_os_waiting_tasks    
 WHERE SESSION = "session"  
END

 

En parallèle la requête suivante est lancée :

SELECT *  
FROM dbo.DatabaseLog AS f  
CROSS JOIN dbo.DatabaseLog AS f2

 

Après avoir lancé une des requêtes avec un niveau d’isolation de transaction en read uncommitted on peut constater que cette dernière a effectivement générée des latchs de type SH dans notre cas :

image

 

On peut regarder à quel objet appartient la page 154 par exemple :

DBCC TRACEON(3604);  
GO    

DBCC PAGE(6, 1, 154) WITH TABLERESULTS;    
GO

 

image

image

 

Pour conclure l’idée que l’utilisation de la lecture sale avec SQL Server ne génère pas de verrous est faussée. Certains les verrous de type S pouvant gêner les écritures sont absents mais  on a pu constater au cours de ce billet que d’autres types de verrous étaient et bien présents ainsi que des latchs pouvant même aboutir à une potentielle contention !!

Bonne utilisation de lecture sale Sourire 

David BARBARIN (Mikedavem)
MVP SQL Server