web-dev-qa-db-fra.com

Comment savoir si une table de base de données est en cours d'accès? Vous voulez quelque chose comme un "déclencheur SELECT"

J'ai une très grande base de données avec des centaines de tables, et après de nombreuses mises à niveau de produits, je suis sûr que la moitié d'entre elles ne sont plus utilisées. Comment savoir si une table est sélectionnée activement? Je ne peux pas simplement utiliser Profiler - non seulement je veux regarder pendant plus de quelques jours, mais il y a aussi des milliers de procédures stockées, et le profileur ne traduira pas les appels SP en appels d'accès à la table.

La seule chose à laquelle je peux penser est de créer un index clusterisé sur les tables d'intérêt, puis de surveiller le sys.dm_db_index_usage_stats pour voir s'il existe des recherches ou des analyses sur l'index clusterisé, ce qui signifie que les données de la table ont été chargées. Cependant, ajouter un index cluster sur chaque table est une mauvaise idée (pour un certain nombre de raisons), car ce n'est pas vraiment faisable.

Y a-t-il d'autres options que j'ai? J'ai toujours voulu une fonctionnalité comme un "déclencheur SELECT", mais il y a probablement d'autres raisons pour lesquelles SQL Server n'a pas cette fonctionnalité non plus.

SOLUTION:

Merci, Remus, de m'avoir pointé dans la bonne direction. En utilisant ces colonnes, j'ai créé le SELECT suivant, qui fait exactement ce que je veux.

  WITH LastActivity (ObjectID, LastAction) AS 
  (
       SELECT object_id AS TableName,
              last_user_seek as LastAction
         FROM sys.dm_db_index_usage_stats u
        WHERE database_id = db_id(db_name())
        UNION 
       SELECT object_id AS TableName,
              last_user_scan as LastAction
         FROM sys.dm_db_index_usage_stats u
        WHERE database_id = db_id(db_name())
        UNION
       SELECT object_id AS TableName,
              last_user_lookup as LastAction
         FROM sys.dm_db_index_usage_stats u
        WHERE database_id = db_id(db_name())
  )
  SELECT OBJECT_NAME(so.object_id) AS TableName,
         MAX(la.LastAction) as LastSelect
    FROM sys.objects so
    LEFT
    JOIN LastActivity la
      on so.object_id = la.ObjectID
   WHERE so.type = 'U'
     AND so.object_id > 100
GROUP BY OBJECT_NAME(so.object_id)
ORDER BY OBJECT_NAME(so.object_id)
56
SqlRyan

Regardez dans sys.dm_db_index_usage_stats . Les colonnes last_user_xxx contiendront la dernière fois que la table a été accédée à partir des demandes des utilisateurs. Ce tableau réinitialise son suivi après un redémarrage du serveur, vous devez donc le laisser fonctionner pendant un certain temps avant de vous fier à ses données.

40
Remus Rusanu

Re: Profiler, si vous surveillez SP: StmtCompleted , qui capturera toutes les instructions exécutées dans une procédure stockée, de sorte que les accès à la table seront capturés dans un sproc. Si tout ne passe pas par des procédures stockées, vous pouvez également avoir besoin de l'événement SQL: StmtCompleted .

Il y aura un grand nombre d'événements, il n'est donc probablement pas pratique de tracer sur une longue période en raison de la taille de la trace. Cependant, vous pouvez appliquer un filtre - par exemple où TextData contient le nom de votre table que vous souhaitez rechercher. Vous pouvez donner une liste de noms de table à filtrer à tout moment et les parcourir progressivement. Vous ne devriez donc pas obtenir d'événements de trace si aucune de ces tables n'a été consultée.

Même si vous pensez que ce n'est pas une approche appropriée/viable pour vous, j'ai pensé que cela valait la peine d'être développé.

Une autre solution serait de faire une recherche globale de votre code source pour trouver des références aux tables. Vous pouvez interroger les définitions de procédure stockée pour vérifier les correspondances pour une table donnée, ou simplement générer un script de base de données complet et effectuer une recherche sur les noms de table.

6
AdaTheDev

Pour SQL Server 2008, vous devriez jeter un œil à Audit SQL . Cela vous permet d'auditer de nombreuses choses, y compris des sélections sur une table et des rapports dans un fichier ou un journal des événements.

3
dr.

La requête suivante utilise le cache de plan de requête pour voir s'il existe une référence à une table dans l'un des plans existants dans le cache. Cette précision n'est pas garantie à 100% (car les plans de requête sont vidés en cas de contraintes de mémoire), mais peut être utilisé pour obtenir des informations sur l'utilisation de la table.

SELECT schema_name(schema_id) as schemaName, t.name as tableName,
    databases.name,
dm_exec_sql_text.text AS TSQL_Text,
dm_exec_query_stats.creation_time, 
dm_exec_query_stats.execution_count,
dm_exec_query_stats.total_worker_time AS total_cpu_time,
dm_exec_query_stats.total_elapsed_time, 
dm_exec_query_stats.total_logical_reads, 
dm_exec_query_stats.total_physical_reads, 
dm_exec_query_plan.query_plan
FROM sys.dm_exec_query_stats 
CROSS APPLY sys.dm_exec_sql_text(dm_exec_query_stats.plan_handle)
CROSS APPLY sys.dm_exec_query_plan(dm_exec_query_stats.plan_handle)
INNER JOIN sys.databases ON dm_exec_sql_text.dbid = databases.database_id
RIGHT JOIN sys.tables t (NOLOCK) ON cast(dm_exec_query_plan.query_plan as varchar(max)) like '%' + t.name + '%'
1

Remarque: si votre intention est de supprimer ces tableaux, vous devrez peut-être tenir compte des obligations légales qui vous imposent de conserver les données impliquées de toute façon pendant x ans.

0
Erwin Smout

J'avais en tête de jouer avec les autorisations utilisateur pour différentes tables, mais je me suis souvenu que vous pouvez activer la trace avec un déclencheur ON LOGON dont vous pourriez bénéficier:

CREATE OR REPLACE TRIGGER SYS.ON_LOGON_ALL

AFTER LOGON ON DATABASE
WHEN (

USER 'MAX'

)
BEGIN

EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE';

--EXECUTE IMMEDIATE 'alter session set events ''10046 trace name context forever level 12''';

EXCEPTION

WHEN OTHERS THEN

NULL;

END;

/

Ensuite, vous pouvez vérifier vos fichiers de trace.

0
Pentium10