Si l’on y prend pas garde, notamment à cause d’une mauvaise administration du serveur, un journal de transaction (JT) peut saturer les disques du serveur. Que faire en cas de problème ? Voici différents scénarios et différents scripts pour parvenir à vos fins.
Les journaux de transactions d’une base de données journalisant en mode FULL ou BULK LOGGED croissent indéfiniment. Seule la sauvegarde du JT permet de réduire la journal. Mais un passage en transitoire mode SIMPLE sans utilisateur connecté permet d’obtenir le même effet, sans pour autant générer un fichier de sauvegarde. Voici quelques script SQL pour ce faire…
NOTA : ces scripts utilisent la fonction RESCRIT dont le code figure à l’entrée suivante « Qualité des données : une fonction de correction des littéraux« .
1 – script de sauvegarde complète de bases de données de production sauf journalisation SIMPLE
Modifiez le contenu de la variable @PATH pour indiquer votre chemin de sauvegarde
DECLARE @PATH NVARCHAR(255); -- chemin de sauvegarde
SET @PATH = 'C:\MesSauvegardes\';
DECLARE @SQL NVARCHAR(max);
SET @SQL = '';
SELECT @SQL = @SQL + 'BACKUP DATABASE [' + DB_NAME(DB.database_id)
+'] TO DISK = ''' + @PATH
+ dbo.F_RESCRIT(DB_NAME(DB.database_id),
'- _.àáâãäçèéêëìíîïñòóôõöùúûüýÿabcdefghijklmnopqrstuvwxyzÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
'____aaaaaceeeeiiiinooooouuuuyyabcdefghijklmnopqrstuvwxyzAAAAACEEEEIIIINOOOOOUUUUYABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
'' )
+ REPLACE(REPLACE(REPLACE(CONVERT(CHAR(19), CURRENT_TIMESTAMP, 121), '-', ''), ' ', '_'), ':', '') + '.BAK'';'
FROM sys.databases AS DB
WHERE DB_NAME(DB.database_id) NOT IN ('master', 'msdb', 'model', 'tempdb', 'distribution')
AND recovery_model_desc <> 'SIMPLE';
EXEC (@SQL);
2 – script de sauvegarde transactionnelle des bases de données de production sauf journalisation SIMPLE
Modifiez le contenu de la variable @PATH pour indiquer votre chemin de sauvegarde
DECLARE @PATH NVARCHAR(255); -- chemin de sauvegarde
SET @PATH = 'C:\MesSauvegardes\';
DECLARE @SQL NVARCHAR(max);
SET @SQL = '';
SELECT @SQL = @SQL + 'BACKUP LOG [' + DB_NAME(DB.database_id)
+'] TO DISK = ''' + @PATH
+ dbo.F_RESCRIT(DB_NAME(DB.database_id),
'- _.àáâãäçèéêëìíîïñòóôõöùúûüýÿabcdefghijklmnopqrstuvwxyzÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
'____aaaaaceeeeiiiinooooouuuuyyabcdefghijklmnopqrstuvwxyzAAAAACEEEEIIIINOOOOOUUUUYABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
'' )
+ REPLACE(REPLACE(REPLACE(CONVERT(CHAR(19), CURRENT_TIMESTAMP, 121), '-', ''), ' ', '_'), ':', '') + '.TRN'';'
FROM sys.databases AS DB
WHERE DB_NAME(DB.database_id) NOT IN ('master', 'msdb', 'model', 'tempdb', 'distribution')
AND recovery_model_desc <> 'SIMPLE';
EXEC (@SQL);
3 – script de passage des bases de données de production en mode de journalisation SIMPLE sauf pour celle utilisant déjà ce mode SIMPLE, de manière transitoire afin de préparer la purge du journal de transaction
DECLARE @SQL NVARCHAR(max);
SET @SQL = 'USE master;CHECKPOINT;';
SELECT @SQL = @SQL + 'USE [' + DB_NAME(DB.database_id) + '];'
+ 'ALTER DATABASE [' + DB_NAME(DB.database_id) +'] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;'
+ 'USE master;'
+ 'ALTER DATABASE [' + DB_NAME(DB.database_id) +'] SET RECOVERY SIMPLE;'
+ 'ALTER DATABASE [' + DB_NAME(DB.database_id) +'] SET MULTI_USER;'
+ 'ALTER DATABASE [' + DB_NAME(DB.database_id) +'] SET RECOVERY FULL;'
FROM sys.databases AS DB
WHERE DB_NAME(DB.database_id) NOT IN ('master', 'msdb', 'model', 'tempdb', 'distribution')
AND recovery_model_desc <> 'SIMPLE';
EXEC (@SQL);
4 – script pour réduire physiquement tous les journaux de transaction des bases de données de production sauf journalisation SIMPLE
DECLARE @SQL NVARCHAR(max);
SET @SQL = '';
SELECT @SQL = @SQL + 'USE [' + DB_NAME(DB.database_id)
+'];DBCC SHRINKFILE (' + CAST(file_id AS VARCHAR(32)) +', 1);'
FROM sys.master_files AS MF
INNER JOIN sys.databases AS DB
ON MF.database_id = DB.database_id
WHERE type_desc = 'LOG'
AND DB_NAME(DB.database_id) NOT IN ('master', 'msdb', 'model', 'tempdb', 'distribution')
AND recovery_model_desc <> 'SIMPLE';
EXEC (@SQL);
Voici une autre façon de faire qui passe la base en mode SIMPLE et revient à son mode normal :
SELECT 'USE [' + d.name +'];'
+ 'ALTER DATABASE [' + d.name +'] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;'
+ 'USE master;'
+ 'ALTER DATABASE [' + d.name +'] SET RECOVERY SIMPLE;'
+ 'USE [' + d.name +'];'
+ 'DBCC SHRINKFILE (''' + mf.name +''', 1);'
+ 'ALTER DATABASE [' + d.name +'] SET RECOVERY ' + recovery_model_desc COLLATE French_BIN2 +';'
+ 'ALTER DATABASE [' + d.name +'] SET MULTI_USER;'
FROM sys.databases AS d
INNER JOIN sys.master_files AS mf
ON d.database_id = mf.database_id
WHERE d.state_desc = 'ONLINE'
AND source_database_id IS NULL
AND recovery_model_desc <> 'SIMPLE'
AND mf.type_desc = 'LOG';
Il suffit de lancer la sortie de cette requête pour réduire drastiquement la taille des journaux de transaction.
--------
Frédéric Brouard, SQLpro - ARCHITECTE DE DONNÉES, http://sqlpro.developpez.com/
Expert bases de données relationnelles et langage SQL. MVP Microsoft SQL Server
www.sqlspot.com : modélisation, conseil, audit, optimisation, tuning, formation
* * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *