web-dev-qa-db-fra.com

Identification des procédures stockées inutilisées

L'année prochaine, j'aide à nettoyer plusieurs environnements SQL Server.

Nous avons environ 10 000 procédures stockées et nous estimons que seulement environ 1 000 d'entre elles sont utilisées régulièrement, et environ 200 autres sont utilisées en de rares occasions, ce qui signifie que nous avons beaucoup de travail à faire.

Puisque nous avons plusieurs départements et équipes qui peuvent accéder à ces bases de données et procédures, nous ne sommes pas toujours ceux qui appellent les procédures, ce qui signifie que nous devons déterminer quelles procédures sont appelées. En plus de cela, nous voulons déterminer cela sur quelques mois, pas dans quelques jours (ce qui élimine certaines possibilités).

Une approche consiste à utiliser le SQL Server Profiler et suivre quelles procédures sont appelées et les comparer à la liste des procédures que nous avons, tout en indiquant si les procédures sont utilisées ou non. À partir de là, nous pourrions déplacer les procédures vers un schéma différent au cas où un service viendrait crier.

L'utilisation de Profiler est-elle l'approche la plus efficace ici? Et/Ou avez-vous fait quelque chose de similaire et trouvé une autre manière/meilleure façon de le faire?

25
Question3CPO

Vous pouvez utiliser trace côté serveur (différent de l'utilisation de l'interface graphique du profileur qui implique plus de ressources) pendant vos tests ou votre cycle commercial et capturer uniquement les éléments liés aux SP. Ensuite, vous pouvez charger cela dans un tableau ou Excel pour une analyse plus approfondie.

La deuxième approche consiste à utiliser DMV sys.dm_exec_procedure_stats (avec la limitation que si le serveur SQL est redémarré, les données sont vidées).

Vous pouvez même planifier un travail pour capturer les données DMV dans une table pour les conserver persistantes.

 -- Get list of possibly unused SPs (SQL 2008 only)
    SELECT p.name AS 'SP Name'        -- Get list of all SPs in the current database
    FROM sys.procedures AS p
    WHERE p.is_ms_shipped = 0

    EXCEPT

    SELECT p.name AS 'SP Name'        -- Get list of all SPs from the current database 
    FROM sys.procedures AS p          -- that are in the procedure cache
    INNER JOIN sys.dm_exec_procedure_stats AS qs
    ON p.object_id = qs.object_id
    WHERE p.is_ms_shipped = 0;

Faire référence à :

33
Kin Shah

Vous pouvez trouver cette question utile, elle s'applique aux tables et aux colonnes mais suggère d'utiliser un outil tiers ApexSQL Clean qui peut également trouver des procédures stockées inutilisées ainsi que tous les objets qui ne sont référencés par aucun autre objet dans ou dans des bases de données externes

Avertissement: je travaille pour ApexSQL en tant qu'ingénieur de support

11
Milica Medic

Si vous utilisez SQL Server 2008+, vous pouvez également utiliser des événements étendus avec un cible d'histogramme . Peut-être que ce serait plus léger qu'une trace.

AFAIK, vous auriez besoin de créer une session différente pour chaque base de données d'intérêt, car je ne voyais aucune indication que le regroupement sur plusieurs colonnes était possible. L'exemple rapide ci-dessous filtre sur database_id=10

CREATE EVENT SESSION [count_module_start_database_10]
ON SERVER
ADD EVENT sqlserver.module_start
(  
        WHERE (source_database_id=10) 
)
ADD TARGET package0.asynchronous_bucketizer
(     SET  filtering_event_name='sqlserver.module_start', 
            source_type=0, 
            source='object_id',
            slots = 10000
)
WITH (MAX_DISPATCH_LATENCY = 5 SECONDS)
GO
ALTER EVENT SESSION [count_module_start_database_10]
ON SERVER
STATE=START

Et puis, après avoir exécuté quelques procédures stockées dans cette base de données plusieurs fois et récupéré les données avec

SELECT CAST(target_data as XML) target_data
FROM sys.dm_xe_sessions AS s 
JOIN sys.dm_xe_session_targets t
    ON s.address = t.event_session_address
WHERE s.name = 'count_module_start_database_10'

La sortie est

<HistogramTarget truncated="0" buckets="16384">
  <Slot count="36">
    <value>1287675635</value>
  </Slot>
  <Slot count="3">
    <value>1271675578</value>
  </Slot>
  <Slot count="2">
    <value>1255675521</value>
  </Slot>
</HistogramTarget>

Montrant que la procédure avec object_id de 1287675635 a été exécuté 36 fois par exemple. Le asynchronous_bucketizer n'est que de la mémoire, il est donc préférable de configurer quelque chose qui l'interroge de temps en temps et le sauvegarde dans un stockage persistant.

10
Martin Smith

Comme suite au script de Kin. Voici un script simple pour créer un tableau pour suivre les utilisations dans le temps et un script pour le mettre à jour périodiquement.

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  Create the use table 
--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CREATE TABLE [dbo].[_ProcedureUseLog](
    [ObjectName] [nvarchar](255) NOT NULL,
    [UseCount] [int] NULL,
    [LastUse] [datetime] NULL,
    [LastCache] [datetime] NULL,
 CONSTRAINT [PK___PROCEDURE_USE] PRIMARY KEY CLUSTERED 
(
    [ObjectName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[_ProcedureUseLog] ADD  CONSTRAINT [DF_Table_1_References]  DEFAULT ((0)) FOR [UseCount]
GO

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  Run this periodically to update the usage stats
--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DECLARE @UsesTable TABLE
(
    ObjectName nvarchar(255),
    Executions int,
    LastUse datetime,
    LastCache datetime
)

INSERT INTO @UsesTable       
SELECT p.name, qs.execution_count, qs.last_execution_time, qs.cached_time
FROM    sys.procedures AS p LEFT OUTER JOIN
        sys.dm_exec_procedure_stats AS qs ON p.object_id = qs.object_id
WHERE        (p.is_ms_shipped = 0)

MERGE [dbo].[_ProcedureUseLog]      AS [Target]
USING @UsesTable                    AS [Source]
    ON Target.ObjectName = Source.ObjectName
WHEN MATCHED AND 
        ( Target.LastCache <> Source.LastCache)
    THEN UPDATE SET
        Target.UseCount = Target.UseCount + Source.Executions,
        Target.LastCache = Source.LastCache,
        Target.LastUse = Source.LastUse
WHEN NOT MATCHED
    THEN INSERT (ObjectName, UseCount, LastUse, LastCache) 
    VALUES      (ObjectName, Executions, LastUse, LastCache);

--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--  This just shows what you've logged so far
--  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SELECT * FROM [_ProcedureUseLog] ORDER BY UseCount DESC
4
James White

Cet article fournit également un script pour trouver des objets non utilisés: Trouver les tables de base de données inutilisées dans SQL Server Ci-dessous est le script de l'article, j'ai changé le type de table "U" en type de procédure stockée "P":

   USE DBName;
   SELECT 

       ao.[name] [Table],
       s.[name] [Schema],
       [create_date] [Created],
        [modify_date] [LastModified]
    FROM
         sys.all_objects ao JOIN sys.schemas s
           ON ao.schema_id = s.schema_id
    WHERE
         OBJECT_ID NOT IN (
              SELECT OBJECT_ID
              FROM sys.dm_db_index_usage_stats
        )
        AND [type] = 'P'
    ORDER BY
        [modify_date] DESC
0
Milica Medic