Cette procédure est destinée à réorganiser le stockage de la base de données système tempdb d’une instance Microsoft SQL Server
NOTA : on trouvera une version exempte des erreurs liés au format de publication de développez.com à l’URL :
http://sqlprofessionnal.wordpress.com/2013/08/17/procedure-de-reorganisation-du-stockage-de-la-base-tempdb-dune-instance-microsoft-sql-server/
GO
IF OBJECT_ID('dbo.P_MOVE_TEMPDB_FILES') IS NOT NULL
EXEC ('DROP PROCEDURE dbo.P_MOVE_TEMPDB_FILES ');
GO
CREATE PROCEDURE dbo.P_MOVE_TEMPDB_FILES
@NBR_FICHIER TINYINT, -- nombre de fichiers de données à créer
@DEST_DATA NVARCHAR(256), -- répertoire destination des données
@SIZE_DATA_GB SMALLINT, -- taille des fichiers de données en Go
@DEST_TRAN NVARCHAR(128), -- répertoire destination des transactions
@SIZE_TRAN_GB SMALLINT, -- taille du journal de transaction en Go
@GROWTH_MB TINYINT -- pas d'incrément des fichiers en Mo
AS
/******************************************************************************
* Procédure modifiant le stockage des fichiers de la base système tempdb *
*******************************************************************************
* Fred. Brouard - http://sqlpro.developpez.com - www.sqlspot.com - 2013-08-16 *
*******************************************************************************
* Cette procédure permet de redessiner le stockage de la BD système tempdb *
* FONCTIONNEMENT : *
* après avoir vérifié les paramètres, la procédure modifie l'organisation du *
* stockage de la base tempdb et fournit un script pour supprimer les fichiers *
* obsolètes. *
*******************************************************************************
* PARAMÈTRES : *
* @NBR_FICHIER : nombre de fichiers de données à créer *
* @DEST_DATA : répertoire de destination des fichiers de données *
* @SIZE_DATA_GB : taille des fichiers de données en Go *
* @DEST_TRAN : répertoire de destination du journal de transaction *
* @SIZE_DATA_GB : taille du journal de transaction en Go *
* @GROWTH_MB : taile en Mo du pas d'incrément de tous les fichiers *
*******************************************************************************
* PROBLÈMES POSSIBLES : *
* - l'utilisateur qui lance cette procédure n'a pas les privilèges adéquats *
* - le compte de service de l'instance SQL Server n'a pas les droits en *
* lecture/ecriture sur le répertoire de destination *
* - le répertoire de destination n'a pas une capacité suffisante pour y *
* stocker les fichiers à déplacer *
* - des fichiers possédant le même nom sont déjà en exploitation dans la *
* destination
* REMÈDE : *
* en cas d'erreur, le résultat (paneau messages de SSMS) fournit la commande *
* qui est partie en exception, mais aussi toute la partie déjà exécutée du *
* script de migration. *
******************************************************************************/
BEGIN
-- variables locales
DECLARE @N TABLE (N TINYINT);
DECLARE @T TABLE (existe BIT, repertoire BIT, parent BIT);
DECLARE @F TABLE (nom_logique sysname,
nom_physique NVARCHAR(384),
nature CHAR(4),
"action" CHAR(6),
destination NVARCHAR(384),
taille_GO SMALLINT);
DECLARE @U TABLE (unite CHAR(1), capacite INT); -- capacité de stockage actuelle
DECLARE @D TABLE (unite CHAR(1), capacite INT); -- volume à stocké
DECLARE @SQL NVARCHAR(max), @SCRIPT NVARCHAR(max), @ERROR NVARCHAR(102);
-- initialisations diverses
SELECT @SIZE_DATA_GB = COALESCE(@SIZE_DATA_GB, 0),
@SIZE_TRAN_GB = COALESCE(@SIZE_TRAN_GB, 0);
INSERT INTO @N VALUES (0), (1), (2), (3);
INSERT INTO @N
SELECT T1.N + T2.N * 4 +T3.N * 16
FROM @N AS T1
CROSS JOIN @N AS T2
CROSS JOIN @N AS T3
WHERE T1.N + T2.N * 4 +T3.N * 16 > 3;
UPDATE @N SET N = N + 1;
-- vérifications diverses :
IF @NBR_FICHIER = 0 OR @NBR_FICHIER IS NULL
BEGIN
RAISERROR('Le nombre de fichiers à spécifier pour les données doit être > 0.',
16, 1);
RETURN;
END;
IF @NBR_FICHIER > 64
BEGIN
RAISERROR('Le nombre de fichiers pour les données (%d) est trop élevé.',
16, 1);
RETURN;
END;
IF @SIZE_DATA_GB < 1
BEGIN
RAISERROR('la taille spécifieé %d pour les données est incorrecte.',
16, 1, @SIZE_DATA_GB);
RETURN;
END;
IF @SIZE_TRAN_GB < 1
BEGIN
RAISERROR('la taille spécifieé %d pour les transactions est incorrecte.',
16, 1, @SIZE_TRAN_GB);
RETURN;
END;
-- les destinations sont-elles bien des répertoires ?
IF RIGHT(@DEST_DATA, 1) '\'
SET @DEST_DATA = @DEST_DATA + N'\';
SET @SQL = 'EXEC sys.xp_fileexist ''' + @DEST_DATA +''';'
INSERT INTO @T EXEC (@SQL);
IF NOT EXISTS(SELECT * FROM @T WHERE repertoire = 1)
BEGIN
RAISERROR('L''emplacement %s n''est pas un répertoire de données.',
16, 1, @DEST_DATA);
RETURN;
END;
DELETE FROM @T;
IF RIGHT(@DEST_TRAN, 1) '\'
SET @DEST_TRAN = @DEST_TRAN + N'\';
SET @SQL = 'EXEC sys.xp_fileexist ''' + @DEST_TRAN +''';'
INSERT INTO @T EXEC (@SQL);
IF NOT EXISTS(SELECT * FROM @T WHERE repertoire = 1)
BEGIN
RAISERROR('L''emplacement %s n''est pas un répertoire de données.',
16, 1, @DEST_TRAN);
RETURN;
END;
-- y a t-il la capacité de stockage ?
INSERT INTO @U
EXEC ('EXEC xp_fixeddrives;');
INSERT INTO @D SELECT LEFT(@DEST_DATA, 1), @NBR_FICHIER * @SIZE_DATA_GB * 1024;
IF LEFT(@DEST_DATA, 1) = LEFT(@DEST_TRAN, 1)
UPDATE @D
SET capacite = capacite + @SIZE_TRAN_GB * 1024
WHERE unite = LEFT(@DEST_TRAN, 1)
ELSE
INSERT INTO @D SELECT LEFT(@DEST_TRAN, 1), @SIZE_TRAN_GB * 1024;
SET @ERROR = N'';
SELECT @ERROR = @ERROR + N' '
+ CAST((D.capacite - U.capacite) / 1024.0 AS NVARCHAR(32))
+ N' Go dans l''unité ' + U.unite + N', '
FROM @U AS U
INNER JOIN @D AS D
ON U.unite = D.unite
WHERE U.capacite < D.capacite;
IF @ERROR N''
BEGIN
SET @ERROR = N'Il manque ' + SUBSTRING(@ERROR, 1, LEN(@ERROR) - 1)
+ N' pour assurer la capacité de stockage demandée.';
RAISERROR(@ERROR, 16, 1, @DEST_TRAN);
RETURN;
END;
-- la procédure xp_cmdshell est-elle utilisable ?
IF NOT EXISTS(SELECT * FROM sys.configurations
WHERE name = 'xp_cmdshell' AND value_in_use = 1)
BEGIN
RAISERROR('La procédure xp_cmdshell nécessaire à l''utilisation
de cette procédure est désactivée. Veuillez contacter
votre adminisrateur de bases de données', 16, 1);
RETURN;
END;
-- on stocke les matadonnées de redéfinition du stockage dans @F
-- fichier à modifier :
INSERT INTO @F
SELECT name, physical_name, type_desc, 'MODIFY',
CASE
WHEN "type" = 0 THEN @DEST_DATA
WHEN "type" = 1 THEN @DEST_TRAN
END + REVERSE(SUBSTRING(REVERSE(physical_name), 1 ,
CHARINDEX('\', REVERSE(physical_name)) -1)),
CASE
WHEN "type" = 0 THEN @SIZE_DATA_GB
WHEN "type" = 1 THEN @SIZE_TRAN_GB
END
FROM sys.master_files AS f
WHERE DB_NAME(database_id) = 'tempdb'
AND file_id 2;
-- fichiers de données à créer :
INSERT INTO @F
SELECT 'tempdata' + CAST(N AS VARCHAR(2)),
NULL,
'ROWS', 'ADD',
@DEST_DATA + 'tempdata' + CAST(N AS VARCHAR(2)) + '.ndf',
@SIZE_DATA_GB
FROM @N
WHERE N BETWEEN 1 AND @NBR_FICHIER - 1;
SET @SCRIPT = N'';
-- construction du script de modification du stockage de tempdb
BEGIN TRY
-- fichiers à modifier
SET @SQL = N'';
SELECT @SQL = @SQL + N'ALTER DATABASE tempdb MODIFY FILE ( NAME = '''
+ nom_logique + N''', FILENAME = '''
+ destination + N''', SIZE = '
+ CAST(taille_GO AS VARCHAR(16)) + N' GB, FILEGROWTH = '
+ CAST(@GROWTH_MB AS VARCHAR(16)) + N' MB);'
FROM @F
WHERE "action" = 'MODIFY';
EXEC (@SQL);
SET @SCRIPT = @SCRIPT + @SQL + NCHAR(13) + NCHAR(10)
+ N'GO' + NCHAR(13) + NCHAR(10);
-- fichiers à supprimer
SET @SQL = N'';
SELECT @SQL = @SQL + N'ALTER DATABASE tempdb REMOVE FILE ['
+ nom_logique + N'];'
FROM @F
WHERE "action" = 'REMOVE';
EXEC (@SQL);
SET @SCRIPT = @SCRIPT + @SQL + NCHAR(13) + NCHAR(10)
+ N'GO' + NCHAR(13) + NCHAR(10);
EXEC (@SQL);
SET @SCRIPT = @SCRIPT + @SQL + NCHAR(13) + NCHAR(10)
+ N'GO' + NCHAR(13) + NCHAR(10);
-- fichiers à ajouter
SET @SQL = N'';
SELECT @SQL = @SQL + N'ALTER DATABASE tempdb ADD FILE ( NAME = '''
+ nom_logique + N''', FILENAME = '''
+ destination + N''', SIZE = '
+ CAST(taille_GO AS VARCHAR(16)) + N' GB, FILEGROWTH = '
+ CAST(@GROWTH_MB AS VARCHAR(16)) + N' MB);'
FROM @F
WHERE "action" = 'ADD';
EXEC (@SQL);
SET @SCRIPT = @SCRIPT + @SQL + NCHAR(13) + NCHAR(10)
+ N'GO' + NCHAR(13) + NCHAR(10);
-- tout s'est bien passé, on informe des fichiers à nettoyer
SELECT nom_physique AS FICHIER_A_SUPPRIMER,
'EXEC xp_cmdshell ''DEL "' + nom_physique +'"'';'
FROM @F
WHERE nom_physique IS NOT NULL
AND nom_physique destination;
END TRY
-- en cas d'ereur...
BEGIN CATCH
SET @ERROR = ERROR_MESSAGE();
RAISERROR('Une erreur est survenur lors de la procédure dbo.P_MOVE_TEMPDB_FILES .', 16, 1);
-- renseigne sur la commande ayant levée l'exception
RAISERROR('L''ereur est survenue lors de la commande : %s', 16, 1, @SQL);
-- renvoie la partie du script déjà exécutée
RAISERROR(@ERROR, 16, 1);
PRINT '--- PARTIE DU SCRIPT DÉJÀ EXÉCUTÉE ---';
PRINT @SCRIPT;
END CATCH
END;
GO
Exemple d’utilisation :
EXEC msdb.dbo.P_MOVE_TEMPDB_FILES
@NBR_FICHIER = 4 , — nombre de fichiers de données à créer
@DEST_DATA = ‘D:\DATABASES\SQL2008R2′, — répertoire destination des données
@SIZE_DATA_GB = 16, — taille des fichiers de données en Go
@DEST_TRAN = ‘E:\DATABASES\SQL2008R2′, — répertoire destination des transactions
@SIZE_TRAN_GB = 10, — taille du journal de transaction en Go
@GROWTH_MB = 100 — pas d’incrément des fichiers en Mo