Affichage des articles dont le libellé est SQL Server. Afficher tous les articles
Affichage des articles dont le libellé est SQL Server. Afficher tous les articles

vendredi 6 février 2015

Liste des processus sous SQL SERVER

Voici un script fort utile pour lister les processus sous SQL SERVER.

Script

SELECT S.*, C.*, R.*,
       MRS.dbid AS DERNIERE_BD_REQUETE, MRS.text AS DERNIERE_REQUETE,
       Q.dbid AS BD_REQUETE, Q.text AS REQUETE,
       P.query_plan AS PLAN_REQUETE
FROM   sys.dm_exec_sessions AS S
       LEFT OUTER JOIN sys.dm_exec_connections AS C 
            ON S.session_id = C.session_id
            OUTER APPLY sys.dm_exec_sql_text(most_recent_sql_handle) AS MRS 
       LEFT OUTER JOIN sys.dm_exec_requests AS R
            ON S.session_id = R.session_id
            OUTER APPLY sys.dm_exec_sql_text(sql_handle) AS Q

            OUTER APPLY sys.dm_exec_query_plan(plan_handle) AS P;

Un exemple d'utilité de ce script : vous devez supprimer ("killer") un processus - il vous suffit juste de récupérer l'identifiant du processus dans  la liste.

vendredi 9 janvier 2015

Rechercher une chaîne de caractères dans une base SQLSERVER

Il peut être utile de rechercher une chaîne de caractères dans tous les composants d'une base SQLSERVER.

Nous allons dans un premier temps déclarer une procédure stockée <sp_Find> qui sera en charge de cette recherche.

Voici le script.

USE [ma_base]
Go

If Exists ( Select 1 
From sys.objects 
Where object_id = object_id(N'dbo.sp_Find') 
And Type = 'P')
Drop Procedure dbo.sp_Find;
Go

Create Procedure [dbo].[sp_Find] 
 @SearchText varchar(8000)
, @DBName sysname = Null
, @PreviewTextSize int = 100
, @SearchDBsFlag char(1) = 'Y'
, @SearchJobsFlag char(1) = 'Y'
, @SearchSSISFlag char(1) = 'Y'
As

Set Transaction Isolation Level Read Uncommitted;
Set Nocount On;

Create Table #FoundObject (
 DatabaseName sysname
, ObjectName sysname
, ObjectTypeDesc nvarchar(60)
, PreviewText varchar(max))

Declare @SQL as nvarchar(max);

Select 'Chercher pour : ''' + @SearchText + '''' As CurrentSearch;

/* rechercher dans les bases utilisateur */

If @SearchDBsFlag = 'Y'
Begin
If @DBName Is Null 
Begin
Declare ObjCursor Cursor Local Fast_Forward For 
Select [Name]
From Master.sys.Databases
Where [Name] Not In ('AdventureWorks', 'AdventureWorksDW', 'Distribution', 'Master', 'MSDB', 'Model', 'TempDB');

Open ObjCursor;

Fetch Next From ObjCursor Into @DBName;
While @@Fetch_Status = 0
Begin
Select @SQL = '
Use [' + @DBName + ']

Insert Into #FoundObject (
 DatabaseName
, ObjectName
, ObjectTypeDesc
, PreviewText)
Select Distinct
 ''' + @DBName + '''
, sch.[Name] + ''.'' + obj.[Name] as ObjectName
, obj.Type_Desc
, Replace(Replace(SubString(mod.Definition, CharIndex(''' + @SearchText + ''', mod.Definition) - ' + Cast(@PreviewTextSize / 2 As varchar) + ', ' + 
Cast(@PreviewTextSize As varchar) + '), char(13) + char(10), ''''), ''' + @SearchText + ''', ''***' + @SearchText + '***'')
From sys.objects obj 
Inner Join sys.SQL_Modules mod On obj.Object_Id = mod.Object_Id
Inner Join sys.Schemas sch On obj.Schema_Id = sch.Schema_Id
Where mod.Definition Like ''%' + @SearchText + '%'' 
Order By ObjectName';

Exec dbo.sp_executesql @SQL;

Fetch Next From ObjCursor Into @DBName;
End;

Close ObjCursor;

Deallocate ObjCursor;
End
Else
Begin
Select @SQL = '
Use [' + @DBName + ']

Insert Into #FoundObject (
 DatabaseName
, ObjectName
, ObjectTypeDesc
, PreviewText)
Select Distinct
 ''' + @DBName + '''
, sch.[Name] + ''.'' + obj.[Name] as ObjectName
, obj.Type_Desc
, Replace(Replace(SubString(mod.Definition, CharIndex(''' + @SearchText + ''', mod.Definition) - ' + Cast(@PreviewTextSize / 2 As varchar) + ', ' + 
Cast(@PreviewTextSize As varchar) + '), char(13) + char(10), ''''), ''' + @SearchText + ''', ''***' + @SearchText + '***'')
From sys.objects obj 
Inner Join sys.SQL_Modules mod On obj.Object_Id = mod.Object_Id
Inner Join sys.Schemas sch On obj.Schema_Id = sch.Schema_Id
Where mod.Definition Like ''%' + @SearchText + '%'' 
Order By ObjectName';

Exec dbo.sp_ExecuteSQL @SQL;
End;

Select 'Database Objects' As SearchType;

Select
 DatabaseName
, ObjectName
, ObjectTypeDesc As ObjectType
, PreviewText
From #FoundObject
Order By DatabaseName, ObjectName;
End

/*  Rechercher dans les Jobs */

If @SearchJobsFlag = 'Y'
Begin
Select 'Job Steps' As SearchType;


Select  j.[Name] As [Job Name]
, s.Step_Id As [Step #]
, Replace(Replace(SubString(s.Command, CharIndex(@SearchText, s.Command) - @PreviewTextSize / 2, @PreviewTextSize), char(13) + char(10), ''), @SearchText, '***' + @SearchText + '***') As Command
From MSDB.dbo.sysJobs j
Inner Join MSDB.dbo.sysJobSteps s On j.Job_Id = s.Job_Id 
Where s.Command Like '%' + @SearchText + '%';
End

/*  Rechercher dans SSIS (packages) */

If @SearchSSISFlag = 'Y'
Begin
Select 'SSIS Packages' As SearchType;

Select  [Name] As [SSIS Name]
, Replace(Replace(SubString(Cast(Cast(PackageData As varbinary(Max)) As varchar(Max)), CharIndex(@SearchText, Cast(Cast(PackageData As varbinary(Max)) As varchar(Max))) -
@PreviewTextSize / 2, @PreviewTextSize), char(13) + char(10), ''), @SearchText, '***' + @SearchText + '***') As [SSIS XML]
From MSDB.dbo.sysDTSPackages90
Where Cast(Cast(PackageData As varbinary(Max)) As varchar(Max)) Like '%' + @SearchText + '%';
End

Go

Comment utiliser cette procédure ?

EXEC dbo.sp_Find 'votre_chaine_a_rechercher', DBName, PreviewTextSize, SearchDBsFlag, SearchJobsFlag, SearchSSISFlag
avec
<DBName> nom d'une base spécifique pour la recherche - par défaut toutes les bases
<PreviewTextSize> nombre de caractères entourant la chaîne de caractères  - à inclure dans le résultat de la recherche
<SearchDBsFlag> recherche dans les bases ? Y ou N
<SearchJobsFlag> recherche dans les Jobs ? Y ou N
<SearchSSISFlag> recherche dans les packages SSIS ? Y ou N

jeudi 8 janvier 2015

Passer une base SQL SERVER du mode SUSPECT au mode NORMAL

Il peut arriver qu'une base se retrouve dans un état "SUSPECT".

Les causes sont multiples mais en général nous sommes dans le cas d'une base "corrompue".

Et lorsque cela arrive, l'accès à cette base est vraiment limité. En clair vous ne pouvez plus l'utiliser correctement.

Comment remédier à ce problème ?

Vous trouverez ci-joint une séquence de commandes à exécuter.

Nous réinitialisons le statut de la base.

EXEC sp_resetstatus 'nom_de_votre_base'
GO

Nous passons la base en mode "réparation" et faisons un "état des lieux"

ALTER DATABASE nom_de_votre_base SET EMERGENCY
DBCC checkdb('nom_de_votre_base')

Nous supprimons les anomalies détectées (ce qui peut provoquer la perte de données)

ALTER DATABASE nom_de_votre_base SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DBCC checkdb('nom_de_votre_base', REPAIR_ALLOW_DATA_LOSS)

Nous repassons la base en mode normal : elle est à nouveau accessible

ALTER DATABASE nom_de_votre_base SET MULTI-USER WITH ROLLBACK IMMEDIATE
GO

Quelques outils pour comprendre la cause du problème

  • Un CHECKDISK sur la partition où se trouve la base
Cela permet de vérifier si le problème est un problème matériel.


  • Vous pouvez consulter les logs.
Exemple :

EXEC sp_readerrorlog 0,1,'2015-01-01'

0 -> log courant, 1 -> error log, '2015-01-01' -> chaine à rechercher dans log, dans notre cas la date du jour par exemple

  • Si dans les erreurs générées par DBCC checkdb('nom_de_ma_base') se trouve des erreurs du type "INDEX"
Nous avons probablement des index incorrects.

Pour lister ces index :

EXEC sp_HelpIndex 'nom_de_ma_table'

  • Vérifier le contenu de la table <msdb.suspect_pages>
Elle vous renseigne sur les pages de données corrompues.

mardi 6 janvier 2015

Défragmenter les index de vos bases SQL SERVER

Comment défragmenter les index de vos bases SQL SERVER ?

Voici un script TRANSACT / SQL fort intéressant et surtout bien pratique.

Dans un premier temps "déclarons" la procédure stockée <dbo.dba_indexDefrag_sp>.

Nous verrons ensuite comment l'utiliser.

Quelques recommandations : soyez attentifs à la taille des TRANSACTION LOG durant le traitement et bien sûr évitez d'exécuter ce traitement durant les heures de travail (consommateur en ressources et en temps CPU).

Script

USE [ma_base]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER Procedure [dbo].[dba_indexDefrag_sp]

    /* Déclarer les paramètres */

      @minFragmentation     float           = 10.0
        /* en pourcentage, si la valeur est inférieure à 10.0 -> aucune défragmentation */

    , @rebuildThreshold     float           = 30.0
        /* en pourcentage, une valeur plus importante va résulter plus d'un REBUILD que d'une réorganisation */

    , @executeSQL           bit             = 1    
        /* 1 = exécuter traitement ; 0 = afficher commandes seulement */

    , @defragOrderColumn    nvarchar(20)    = 'range_scan_count'
        /* options valides : range_scan_count, fragmentation, page_count 

Permet de définir les priorités dans l'ordre des defrags.  Utilisé uniquement si @executeSQL = 1.

range_scan_count = en général, c'est le plus profitable pour la défragmentation
fragmentation  = valeur de la fragmentation dans l'index;
                                               plus la valeur est haute, plus la fragmentation est importante
page_count  = nombre de pages dans l'index ; effet sur la durée du defrag de l'index
*/

    , @defragSortOrder      nvarchar(4)     = 'DESC'
        /* options valides : ASC, DESC */

    , @timeLimit            int             = 720
        /* limitation de temps optionnelle : exprimée en minutes */

    , @database             varchar(128)    = N'ma_base'
        /* option pour spécifier un nom de base ; null correspond à toutes les bases */

    , @tableName            varchar(4000)   = Null 
        /* option pour spécifier une table ; null correspond à toutes les tables */

    , @forceRescan          bit             = 0
        /* Pour forcer ou pas un rescan des index ; 1 = force, 0 = utilise scan existant si disponible */

    , @scanMode             varchar(10)     = N'LIMITED'
        /* Options sont LIMITED (le plus rapide, seul le plus haut niveau <parent> est scanné), SAMPLED (un % des pages DATA), et DETAILED (toutes les pages DATA) */

    , @minPageCount         int             = 8
        /*  Minimum de pages pour déclencher le traitement - Microsoft recommende > 1 extent (8 pages) */

    , @maxPageCount         int             = Null
        /* Maximum de pages pour déclencher le traitement - NULL = pas de limite */

    , @excludeMaxPartition  bit             = 0
        /* 1 = exclure partition la plus "populée" ;  0 = ne pas exclure */

    , @onlineRebuild        bit             = 1  
        /* 1 = rebuild online ; 0 = rebuild offline seulement pour l'édition Entreprise */

    , @sortInTempDB         bit             = 1
        /* 1 = exécute opération de tri dans TempDB ; 0 = exécute opération de tri dans la base */

    , @maxDopRestriction    tinyint         = Null
        /* option pour réduite le nombre de processeurs pour l'opération seulement dans l'édition Entreprise */

    , @printCommands        bit             = 0  
        /* 1 = afficher commandes à l'écran ; 0 = ne pas afficher commandes */

    , @printFragmentation   bit             = 0
        /* 1 = afficher fragmentation à l'écran;
           0 = ne pas imprimer */

    , @defragDelay          char(8)         = '00:00:05'
        /* durée d'attente entre 2 commandes defrag */

    , @debugMode            bit             = 0
        /* 1 : afficher commentaires debug ; 0 : ne pas afficher commentaires debug */

As

Set NoCount On;
Set XACT_Abort On;
Set Quoted_Identifier On;

Begin

    Begin Try

        If @minFragmentation Is Null
            Or @minFragmentation Not Between 0.00 And 100.0
                Set @minFragmentation = 10.0;

        If @rebuildThreshold Is Null
            Or @rebuildThreshold Not Between 0.00 And 100.0
                Set @rebuildThreshold = 30.0;

        If @defragDelay Not Like '00:[0-5][0-9]:[0-5][0-9]'
            Set @defragDelay = '00:00:05';

        If @defragOrderColumn Is Null
            Or @defragOrderColumn Not In ('range_scan_count', 'fragmentation', 'page_count')
                Set @defragOrderColumn = 'range_scan_count';

        If @defragSortOrder Is Null
            Or @defragSortOrder Not In ('ASC', 'DESC')
                Set @defragSortOrder = 'DESC';

        If @scanMode Not In ('LIMITED', 'SAMPLED', 'DETAILED')
            Set @scanMode = 'LIMITED';

        If @debugMode Is Null
            Set @debugMode = 0;

        If @forceRescan Is Null
            Set @forceRescan = 0;

        If @sortInTempDB Is Null
            Set @sortInTempDB = 1;

        If @debugMode = 1 RaisError('Initialisation et démarrage traitement...', 0, 42) With NoWait;

        Declare   @objectID                 int
                , @databaseID               int
                , @databaseName             nvarchar(128)
                , @indexID                  int
                , @partitionCount           bigint
                , @schemaName               nvarchar(128)
                , @objectName               nvarchar(128)
                , @indexName                nvarchar(128)
                , @partitionNumber          smallint
                , @fragmentation            float
                , @pageCount                int
                , @sqlCommand               nvarchar(4000)
                , @rebuildCommand           nvarchar(200)
                , @dateTimeStart            datetime
                , @dateTimeEnd              datetime
                , @containsLOB              bit
                , @editionCheck             bit
                , @debugMessage             nvarchar(4000)
                , @updateSQL                nvarchar(4000)
                , @partitionSQL             nvarchar(4000)
                , @partitionSQL_Param       nvarchar(1000)
                , @LOB_SQL                  nvarchar(4000)
                , @LOB_SQL_Param            nvarchar(1000)
                , @indexDefrag_id           int
                , @startDateTime            datetime
                , @endDateTime              datetime
                , @getIndexSQL              nvarchar(4000)
                , @getIndexSQL_Param        nvarchar(4000)
                , @allowPageLockSQL         nvarchar(4000)
                , @allowPageLockSQL_Param   nvarchar(4000)
                , @allowPageLocks           int
                , @excludeMaxPartitionSQL   nvarchar(4000);

        Select @startDateTime = GetDate()
            , @endDateTime = DateAdd(minute, @timeLimit, GetDate());

        Create Table #databaseList
        (
              databaseID        int
            , databaseName      varchar(128)
            , scanStatus        bit
        );

        Create Table #processor
        (
              [index]           int
            , Name              varchar(128)
            , Internal_Value    int
            , Character_Value   int
        );

        Create Table #maxPartitionList
        (
              databaseID        int
            , objectID          int
            , indexID           int
            , maxPartition      int
        );

        If @debugMode = 1 RaisError('Début validation...', 0, 42) With NoWait;

        Insert Into #processor
        Execute xp_msver 'ProcessorCount';

        If @maxDopRestriction Is Not Null And @maxDopRestriction > (Select Internal_Value From #processor)
            Select @maxDopRestriction = Internal_Value
            From #processor;

        /* Vérifions version server ; 1804890536 = Entreprise, 610778273 = Entreprise Evaluation, -2117995310 = Développeur */
        If (Select ServerProperty('EditionID')) In (1804890536, 610778273, -2117995310)
            Set @editionCheck = 1 
        Else
            Set @editionCheck = 0; 

/* liste des tables à traiter */
        Insert Into #databaseList
        Select database_id
            , name
            , 0 
        From sys.databases
        Where name = IsNull(@database, name)
            And [name] Not In ('master', 'tempdb')
            And [state] = 0
            And is_read_only = 0;

        If Not Exists(Select Top 1 * From dbo.dba_indexDefragStatus Where defragDate Is Null)
            Or @forceRescan = 1
        Begin

            Truncate Table dbo.dba_indexDefragStatus;

// traiter les tables
            While (Select Count(*) From #databaseList Where scanStatus = 0) > 0
            Begin

                Select Top 1 @databaseID = databaseID
                From #databaseList
                Where scanStatus = 0;

                Select @debugMessage = '  traitement table ' + DB_Name(@databaseID) + '...';

                If @debugMode = 1
                    RaisError(@debugMessage, 0, 42) With NoWait;

                Insert Into dbo.dba_indexDefragStatus
                (
                      databaseID
                    , databaseName
                    , objectID
                    , indexID
                    , partitionNumber
                    , fragmentation
                    , page_count
                    , range_scan_count
                    , scanDate
                )
                Select
                      ps.database_id As 'databaseID'
                    , QuoteName(DB_Name(ps.database_id)) As 'databaseName'
                    , ps.object_id As 'objectID'
                    , ps.index_id As 'indexID'
                    , ps.partition_number As 'partitionNumber'
                    , Sum(ps.avg_fragmentation_in_percent) As 'fragmentation'
                    , Sum(ps.page_count) As 'page_count'
                    , os.range_scan_count
                    , GetDate() As 'scanDate'
                From sys.dm_db_index_physical_stats(@databaseID, Object_Id(@tableName), Null , Null, @scanMode) As ps
                Join sys.dm_db_index_operational_stats(@databaseID, Object_Id(@tableName), Null , Null) as os
                    On ps.database_id = os.database_id
                    And ps.object_id = os.object_id
                    and ps.index_id = os.index_id
                    And ps.partition_number = os.partition_number
                Where avg_fragmentation_in_percent >= @minFragmentation
                    And ps.index_id > 0
                    And ps.page_count > @minPageCount
                    And ps.index_level = 0
                Group By ps.database_id
                    , QuoteName(DB_Name(ps.database_id))
                    , ps.object_id
                    , ps.index_id
                    , ps.partition_number
                    , os.range_scan_count
                Option (MaxDop 2);

                If @excludeMaxPartition = 1
                Begin

                    Set @excludeMaxPartitionSQL = '
                        Select ' + Cast(@databaseID As varchar(10)) + ' As [databaseID]
                            , [object_id]
                            , index_id
                            , Max(partition_number) As [maxPartition]
                        From ' + DB_Name(@databaseID) + '.sys.partitions
                        Where partition_number > 1
                            And [rows] > 0
                        Group By object_id
                            , index_id;';

                    Insert Into #maxPartitionList
                    Execute sp_executesql @excludeMaxPartitionSQL;

                End;
             
                Update #databaseList
                Set scanStatus = 1
                Where databaseID = @databaseID;

            End

            If @excludeMaxPartition = 1
            Begin

                Delete ids
                From dbo.dba_indexDefragStatus As ids
                Join #maxPartitionList As mpl
                    On ids.databaseID = mpl.databaseID
                    And ids.objectID = mpl.objectID
                    And ids.indexID = mpl.indexID
                    And ids.partitionNumber = mpl.maxPartition;

            End;

            Update ids
            Set ids.exclusionMask = ide.exclusionMask
            From dbo.dba_indexDefragStatus As ids
            Join dbo.dba_indexDefragExclusion As ide
                On ids.databaseID = ide.databaseID
                And ids.objectID = ide.objectID
                And ids.indexID = ide.indexID;
       
        End

// les index à défragmenter
        Select @debugMessage = 'Nous avons  ' + Cast(Count(*) As varchar(10)) + '  index à défragmenter !'
        From dbo.dba_indexDefragStatus
        Where defragDate Is Null
            And page_count Between @minPageCount And IsNull(@maxPageCount, page_count);

        If @debugMode = 1 RaisError(@debugMessage, 0, 42) With NoWait;

        While (Select Count(*)
               From dbo.dba_indexDefragStatus
               Where (
                           (@executeSQL = 1 And defragDate Is Null)
                        Or (@executeSQL = 0 And defragDate Is Null And printStatus = 0)
                     )
                And exclusionMask & Power(2, DatePart(weekday, GetDate())-1) = 0
                And page_count Between @minPageCount And IsNull(@maxPageCount, page_count)) > 0
        Begin

            If IsNull(@endDateTime, GetDate()) < GetDate()
            Begin
                RaisError('Limite temps dépassé !', 11, 42) With NoWait;
            End;

            Set @getIndexSQL = N'
            Select Top 1
                  @objectID_Out         = objectID
                , @indexID_Out          = indexID
                , @databaseID_Out       = databaseID
                , @databaseName_Out     = databaseName
                , @fragmentation_Out    = fragmentation
                , @partitionNumber_Out  = partitionNumber
                , @pageCount_Out        = page_count
            From dbo.dba_indexDefragStatus
            Where defragDate Is Null '
                + Case When @executeSQL = 0 Then 'And printStatus = 0' Else '' End + '
                And exclusionMask & Power(2, DatePart(weekday, GetDate())-1) = 0
                And page_count Between @p_minPageCount and IsNull(@p_maxPageCount, page_count)
            Order By + ' + @defragOrderColumn + ' ' + @defragSortOrder;
                     
            Set @getIndexSQL_Param = N'@objectID_Out        int OutPut
                                     , @indexID_Out         int OutPut
                                     , @databaseID_Out      int OutPut
                                     , @databaseName_Out    nvarchar(128) OutPut
                                     , @fragmentation_Out   int OutPut
                                     , @partitionNumber_Out int OutPut
                                     , @pageCount_Out       int OutPut
                                     , @p_minPageCount      int
                                     , @p_maxPageCount      int';

            Execute sp_executesql @getIndexSQL
                , @getIndexSQL_Param
                , @p_minPageCount       = @minPageCount
                , @p_maxPageCount       = @maxPageCount
                , @objectID_Out         = @objectID OutPut
                , @indexID_Out          = @indexID OutPut
                , @databaseID_Out       = @databaseID OutPut
                , @databaseName_Out     = @databaseName OutPut
                , @fragmentation_Out    = @fragmentation OutPut
                , @partitionNumber_Out  = @partitionNumber OutPut
                , @pageCount_Out        = @pageCount OutPut;

            Select @updateSQL = N'Update ids
                Set schemaName = QuoteName(s.name)
                    , objectName = QuoteName(o.name)
                    , indexName = QuoteName(i.name)
                From dbo.dba_indexDefragStatus As ids
                Inner Join ' + @databaseName + '.sys.objects As o
                    On ids.objectID = o.object_id
                Inner Join ' + @databaseName + '.sys.indexes As i
                    On o.object_id = i.object_id
                    And ids.indexID = i.index_id
                Inner Join ' + @databaseName + '.sys.schemas As s
                    On o.schema_id = s.schema_id
                Where o.object_id = ' + Cast(@objectID As varchar(10)) + '
                    And i.index_id = ' + Cast(@indexID As varchar(10)) + '
                    And i.type > 0
                    And ids.databaseID = ' + Cast(@databaseID As varchar(10));

            Execute sp_executesql @updateSQL;

            Select @objectName  = objectName
                , @schemaName   = schemaName
                , @indexName    = indexName
            From dbo.dba_indexDefragStatus
            Where objectID = @objectID
                And indexID = @indexID
                And databaseID = @databaseID;

            Select @partitionSQL = 'Select @partitionCount_OUT = Count(*)
                                        From ' + @databaseName + '.sys.partitions
                                        Where object_id = ' + Cast(@objectID As varchar(10)) + '
                                            And index_id = ' + Cast(@indexID As varchar(10)) + ';'
                , @partitionSQL_Param = '@partitionCount_OUT int OutPut';

            Execute sp_executesql @partitionSQL, @partitionSQL_Param, @partitionCount_OUT = @partitionCount OutPut;
   
            /* Déterminer si la table contient des LOB (Large Objects)
            Select @LOB_SQL = ' Select @containsLOB_OUT = Count(*)
                                From ' + @databaseName + '.sys.columns With (NoLock)
                                Where [object_id] = ' + Cast(@objectID As varchar(10)) + '
                                   And (system_type_id In (34, 35, 99)
                                            Or max_length = -1);'
                                /*  system_type_id --> 34 = image, 35 = text, 99 = ntext
                                    max_length = -1 --> varbinary(max), varchar(max), nvarchar(max), xml */
                    , @LOB_SQL_Param = '@containsLOB_OUT int OutPut';

            Execute sp_executesql @LOB_SQL, @LOB_SQL_Param, @containsLOB_OUT = @containsLOB OutPut;

            /* Déterminer si verrous sur page sont autorisés ; pour de tels index nou avons toujours besoin d'effectuer un REBUILD */
            Select @allowPageLockSQL = 'Select @allowPageLocks_OUT = Count(*)
                                        From ' + @databaseName + '.sys.indexes
                                        Where object_id = ' + Cast(@objectID As varchar(10)) + '
                                            And index_id = ' + Cast(@indexID As varchar(10)) + '
                                            And Allow_Page_Locks = 0;'
                , @allowPageLockSQL_Param = '@allowPageLocks_OUT int OutPut';

            Execute sp_executesql @allowPageLockSQL, @allowPageLockSQL_Param, @allowPageLocks_OUT = @allowPageLocks OutPut;

            /* S'il y a un taux élevé de fragmentation ou si nous avons un LOB, nous devons réorganiser */
            If (@fragmentation < @rebuildThreshold Or @containsLOB >= 1 Or @partitionCount > 1)
                And @allowPageLocks = 0
            Begin
         
                Set @sqlCommand = N'Alter Index ' + @indexName + N' On ' + @databaseName + N'.'
                                    + @schemaName + N'.' + @objectName + N' ReOrganize';

                /* si notre index est partitionné, nous devons toujours réorganiser */
                If @partitionCount > 1
                    Set @sqlCommand = @sqlCommand + N' Partition = '
                                    + Cast(@partitionNumber As nvarchar(10));

            End

            /* Si l'index est très fragmenté et ne contient pas plusieurs partitions ou ne contient pas de LOB,
               ou si l'index n'autorise pas les verrous sur page => REBUILD pour index */
            Else If (@fragmentation >= @rebuildThreshold Or @allowPageLocks <> 0)
                And IsNull(@containsLOB, 0) != 1 And @partitionCount <= 1
            Begin

                If @onlineRebuild = 1 And @editionCheck = 1
                    Set @rebuildCommand = N' Rebuild With (Online = On';
                Else
                    Set @rebuildCommand = N' Rebuild With (Online = Off';
             
                If @sortInTempDB = 1
                    Set @rebuildCommand = @rebuildCommand + N', Sort_In_TempDB = On';
                Else
                    Set @rebuildCommand = @rebuildCommand + N', Sort_In_TempDB = Off';

                   If @maxDopRestriction Is Not Null And @editionCheck = 1
                    Set @rebuildCommand = @rebuildCommand + N', MaxDop = ' + Cast(@maxDopRestriction As varchar(2)) + N')';
                Else
                    Set @rebuildCommand = @rebuildCommand + N')';

                Set @sqlCommand = N'Alter Index ' + @indexName + N' On ' + @databaseName + N'.'
                                + @schemaName + N'.' + @objectName + @rebuildCommand;

            End
            Else
                If @printCommands = 1 Or @debugMode = 1
                    RaisError('Impossible de défragmenter cet index !', 0, 42) With NoWait;

            If @executeSQL = 1
            Begin

                Set @debugMessage = 'Exécuter : ' + @sqlCommand;
             
                If @printCommands = 1 Or @debugMode = 1
                    RaisError(@debugMessage, 0, 42) With NoWait;

               Set @dateTimeStart  = GetDate();

                Insert Into dbo.dba_indexDefragLog
                (
                      databaseID
                    , databaseName
                    , objectID
                    , objectName
                    , indexID
                    , indexName
                    , partitionNumber
                    , fragmentation
                    , page_count
                    , dateTimeStart
                    , sqlStatement
                )
                Select
                      @databaseID
                    , @databaseName
                    , @objectID
                    , @objectName
                    , @indexID
                    , @indexName
                    , @partitionNumber
                    , @fragmentation
                    , @pageCount
                    , @dateTimeStart
                    , @sqlCommand;

                Set @indexDefrag_id = Scope_Identity();

                Begin Try

                    Execute sp_executesql @sqlCommand;
                    Set @dateTimeEnd = GetDate();
                 
                    Update dbo.dba_indexDefragLog
                    Set dateTimeEnd = @dateTimeEnd
                        , durationSeconds = DateDiff(second, @dateTimeStart, @dateTimeEnd)
                    Where indexDefrag_id = @indexDefrag_id;

                End Try
                Begin Catch

                    Update dbo.dba_indexDefragLog
                    Set dateTimeEnd = GetDate()
                        , durationSeconds = -1
                        , errorMessage = Error_Message()
                    Where indexDefrag_id = @indexDefrag_id;

                    If @debugMode = 1
                        RaisError('Erreur lors de l'exécution de cette commande - consulter la table dba_indexDefragLog pour plus de détails', 0, 42) With NoWait;

                End Catch

                WaitFor Delay @defragDelay;

                Update dbo.dba_indexDefragStatus
                Set defragDate = GetDate()
                    , printStatus = 1
                Where databaseID       = @databaseID
                  And objectID         = @objectID
                  And indexID          = @indexID
                  And partitionNumber  = @partitionNumber;

            End
            Else
   
            Begin
               
                If @printCommands = 1 Or @debugMode = 1
                    Print IsNull(@sqlCommand, 'erreur !');

                Update dbo.dba_indexDefragStatus
                Set printStatus = 1
                Where databaseID       = @databaseID
                  And objectID         = @objectID
                  And indexID          = @indexID
                  And partitionNumber  = @partitionNumber;
            End

        End

        /* résumé du traitement */
        If @printFragmentation = 1
        Begin

            If @debugMode = 1 RaisError(' Afficher résumé traitement...', 0, 42) With NoWait;

            Select databaseID
                , databaseName
                , objectID
                , objectName
                , indexID
                , indexName
                , partitionNumber
                , fragmentation
                , page_count
                , range_scan_count
            From dbo.dba_indexDefragStatus
            Where defragDate >= @startDateTime
            Order By defragDate;

        End;

    End Try
    Begin Catch

        Set @debugMessage = Error_Message() + ' (Numéro de ligne : ' + Cast(Error_Line() As varchar(10)) + ')';
        Print @debugMessage;

    End Catch;

    Drop Table #databaseList;
    Drop Table #processor;
    Drop Table #maxPartitionList;

    Set NoCount Off;
    Return 0

End

Comment utiliser cette procédure stockée ?

Voici un exemple d'utilisation :

Exec dbo.dba_indexDefrag_sp
              @executeSQL           = 1
            , @printCommands        = 1
            , @debugMode            = 1
            , @printFragmentation   = 1
            , @forceRescan          = 1
            , @maxDopRestriction    = 1
            , @minPageCount         = 8
            , @maxPageCount         = Null
            , @minFragmentation     = 1
            , @rebuildThreshold     = 30
            , @defragDelay          = '00:00:05'
            , @defragOrderColumn    = 'page_count'
            , @defragSortOrder      = 'DESC'
            , @excludeMaxPartition  = 1
            , @timeLimit            = Null;

Nous vous conseillons de "packager" cet exemple dans un JOB (SQL Agent JOB) ou de l'exécuter en mode commande.