Dévoiler les commandes DBCC cachées

Héritées de Sybase qui fut à l’origine du produit Microsoft SQL Server en 1989, les instructions DBCC constituent un ensemble de commandes à fonctionnalités diverses. Seules quelques unes sont documentées, mais il en existe de nombreuses autres : comment dévoiler les commandes DBCC cachées ?

Dans les anciennes documentations (version 7.0 et antérieures), DBCC signifiait « Database Consistency Checker » (en français « Vérificateur de cohérence de base de données »). Bien que certaines de ces instructions soient bien destinées à cet usage, le jeu de commandes DBCC est devenu le « fourre-tout » du langage Transact-SQL, pour toute une série de commandes qui ne rentrent pas dans le cadre du langage SQL déterminé par la norme ANSI. On y trouve ainsi des commandes renvoyant des informations ou des statistiques sur le moteur ou la base de données, des commandes de maintenance, ou des commandes à usage divers. Dans les documentations actuelles (et ce depuis la version 2000), DBCC est maintenant traduit par « DataBase Console Command » (en français « Commande de console de base de données »), ce qui semble plus près de la réalité.

Autre particularités des instructions DBCC, on constate que leur nombre est bien plus étendu que ne le laisse supposer la documentation : il existe de nombreuses commandes "internes" non documentées.
Pour obtenir la liste des commandes DBCC, il faut utiliser ... une commande DBCC :

    DBCC HELP ('?')

nous renvoie la liste des commandes disponibles (32 en SQL 2012).

La même commande nous permet d'obtenir une aide (concise) sur la syntaxe :

    DBCC HELP ('HELP')

nous fournit la syntaxe ... de la commande DBCC HELP !
Les commandes cachées

Nous savons qu'il existe bien d'autres commandes DBCC internes. En activant le drapeau de trace 2588  (en SQL2000 c'était le 2520), nous obtiendrons la liste complète :

    DBCC TRACEON (2588) -- SQL 2005 et ultérieur
    DBCC HELP ('?')

Nous avons maintenant 95 commandes (en SQL 2012) !

Attention, l’usage de commandes ou de fonctionnalités non documentées est à vos risques et périls et ne doit jamais être testée sur un serveur en production !

Pour les commandes non documentées, il est souvent nécessaire d’activer le renvoi des résultats de trace au client, sinon la commande s'exécutera sans renvoyer aucun résultat. Avant de les exécuter il faut donc activer le drapeau de trace 3604 pour la connexion en cours :

    DBCC TRACEON (3604)

Quelques commandes :

La plupart des commandes sont à usage interne et sont utilisées par des procédures système (sp_) : par exemple, DBCC ADDINSTANCE, SETINSTANCE, INCREMENTINSTANCE, DELETEINSTANCE sont utilisées pour gérer les instances des agents de réplication, DBCC AUDITEVENT est utilisée par les procédures stockées de sécurité (sp_addlogin, sp_addrole, sp_addrolemember, ...)

Beaucoup de commandes font désormais double emploi avec des vues de gestion dynamique (dmv) et sont plus utilisées que par habitude. Certaines sont cependant utiles (et utilisées) pour obtenir de l'information. En voici quelques unes :

DBCC BUFFER : Syntaxe : DBCC buffer ( {'dbname' | dbid} [, objid [, number [, printopt={0|1|2} ][, dirty | io | kept | rlock | ioerr | hashed ]]])
Usage : Cette commande permet de renvoyer le contenu des pages depuis le cache de données (buffer cache). L’option printopt permet différentes présentations :
0 – Uniquement l’entête du tampon et l’entête de page (par défaut)
1 – Chaque ligne séparément et la table d’offset
2 - Chaque ligne dans sont ensemble et la table d’offset

DBCC LOGINFO : Syntaxe : DBCC loginfo [({'database_name' | dbid})]
Usage : Renvoie les informations sur le journal de transaction, ses fichiers virtuels (VLF : Virtual log files) et les parties actives du journal.

DBCC IND
: Syntaxe : DBCC ind ( { 'dbname' | dbid }, { 'objname' | objid }, { indid | 0 | -1 | -2 } )
Usage : Renvoie un rapport sur toutes les pages utilisées par des index. Depuis SQL 2012, on peut aussi utiliser la DMV sys.dm_db_database_page_allocations

DBCC PAGE : Syntaxe : DBCC page ( {'dbname' | dbid}, filenum, pagenum [, printopt={0|1|2|3} ][, cache={0|1} ])
Usage : Permet de visualiser le contenu d’une page. L’option printopt permet différentes présentations :
0 – Uniquement l’entête
1 – Entête, dump de chaque ligne et table d’offset de la page
2 -  Entête, dump de la page et table d’offset de la page
3 – Entête, dump de chaque ligne et affichage de l’enregistrement en clair
L’option cache permet d’obtenir la page du cache (1, par défaut) ou en la lisant sur disque (0)
Comment trouver les numéros du fichier et de page de la première page de la table (paramètres filenum et pagenum) ?
Le numéro de la page recherchée peut être obtenu dans la table sysindexes (la colonne first contient la référence à la première page de la table).
Exemple :
Use northwind
Select first from sysindexes
WHERE id = object_id ('customers')
AND indid in (0, 1)

** résultat **
first         
--------------
0x870100000100

Dans l’exemple ci-dessus, le résultat est une valeur hexadécimale 0x870100000100. Vous devez la convertir en numéro de fichier et numéro de page. En notation hexa, chaque jeu de 2 caractères représente un octet. La valeur renvoyée contient ces éléments dans un format où les octets sont inversés.
- Le numéro de fichier correspond aux deux derniers octets (inversés) : la valeur hexa 0x0001 correspond au numéro de fichier 1 en décimal
- Le numéro de page correspond aux 4 octets premiers octets (inversés) : la valeur hexa 0x00000187 correspond au numéro de page 391 en décimal.
(Vous pouvez vous aider de la calculatrice Windows pour effectuer la conversion hexa vers décimal).


Nous ne ferons pas ici la liste exhaustive, cela laisse la place à quelques posts futurs... et à votre propre exploration !