Trouver quelle session contient quelle table temporaire


14

Nous avons une base de données SQL Server 2005, la base de données temporaire est pleine. En allant dans SQL Server Management Studio, je peux voir toutes les tables temporaires dans tempdb. Est-il possible de dire quelle session contient quelle table temporaire? Idéalement, une requête répertoriant les tables temporaires utilisées par chaque session.

Merci,


1
Nous aimerions retrouver l'utilisateur spécifique qui utilise l'espace dans la base de données temporaire. C'est la consommation actuelle de tempdb par les tâches qui nous intéresse.
SQLMIKE

Réponses:


16

J'ai demandé que quelque chose soit intégré en 2007, sur Connect. Cela a été rejeté pour la version 2008, puis ignoré, jusqu'à ce que Connect meure il y a quelques années. J'ai essayé de le trouver sur le nouveau site de commentaires pour SQL Server , mais cette recherche est un véritable incendie. Le titre de ma demande était "dmv pour mapper la table temporaire vers session_id" - puisque la recherche ne peut faire que OU, "la table temporaire de la carte" renvoie 118 pages de résultats. Google semble suggérer que l'article n'a pas été coupé lorsqu'il a tué Connect .

En attendant, pour SQL Server 2005 et 2008, vous devriez pouvoir extraire ces informations de la trace par défaut:

DECLARE @FileName VARCHAR(MAX)  

SELECT @FileName = SUBSTRING(path, 0,
   LEN(path)-CHARINDEX('\', REVERSE(path))+1) + '\Log.trc'  
FROM sys.traces   
WHERE is_default = 1;  

SELECT   
     o.name,   
     o.OBJECT_ID,  
     o.create_date, 
     gt.NTUserName,  
     gt.HostName,  
     gt.SPID,  
     gt.DatabaseName,  
     gt.TEXTData 
FROM sys.fn_trace_gettable( @FileName, DEFAULT ) AS gt  
JOIN tempdb.sys.objects AS o   
     ON gt.ObjectID = o.OBJECT_ID  
WHERE gt.DatabaseID = 2 
  AND gt.EventClass = 46 -- (Object:Created Event from sys.trace_events)  
  AND o.create_date >= DATEADD(ms, -100, gt.StartTime)   
  AND o.create_date <= DATEADD(ms, 100, gt.StartTime)

Sorti sans vergogne de ce billet de blog de Jonathan Kehayias .

Pour déterminer l'utilisation de l'espace, vous pouvez encore améliorer cela pour joindre des données à partir de vues comme sys.db_db_partition_stats- par exemple:

DECLARE @FileName VARCHAR(MAX)  

SELECT @FileName = SUBSTRING(path, 0,
   LEN(path)-CHARINDEX('\', REVERSE(path))+1) + '\Log.trc'  
FROM sys.traces   
WHERE is_default = 1;  

SELECT   
     o.name,   
     o.OBJECT_ID,  
     o.create_date, 
     gt.NTUserName,  
     gt.HostName,  
     gt.SPID,  
     gt.DatabaseName,  
     gt.TEXTData,
     row_count = x.rc,
     used_page_count = x.upc
FROM sys.fn_trace_gettable( @FileName, DEFAULT ) AS gt  
JOIN tempdb.sys.objects AS o   
     ON gt.ObjectID = o.OBJECT_ID
INNER JOIN
(
 SELECT [object_id], SUM(row_count), SUM(used_page_count)
   FROM tempdb.sys.dm_db_partition_stats
   WHERE index_id IN (0,1)
   GROUP BY [object_id]
) AS x(id, rc, upc)
ON x.id = o.[object_id]
WHERE gt.DatabaseID = 2 
  AND gt.EventClass = 46 -- (Object:Created Event from sys.trace_events)  
  AND o.create_date >= DATEADD(ms, -100, gt.StartTime)   
  AND o.create_date <= DATEADD(ms, 100, gt.StartTime)

Le problème ici est d'essayer de corréler un nom de table par le texte de la requête; ce n'est tout simplement pas pratique, car la plupart du temps, l'utilisateur n'exécute toujours pas de requête sur cette table (sans parler de l'exécution de celle qui l'a créée / remplie).

Cependant, et c'est pour les autres lecteurs (ou pour vous lorsque vous effectuez une mise à niveau), la trace par défaut dans 2012+ ne suit plus la création d'objets de table temporaire , si la table #temp est un tas. Je ne sais pas si c'est une coïncidence ou directement liée au fait qu'à partir de 2012, toutes les tables temporaires ont maintenant un négatifobject_id . Vous pouvez bien sûr passer à Événements étendus pour vous aider à collecter et suivre ces informations, mais cela peut être beaucoup de travail manuel (et j'ai seulement vérifié que ce n'est plus suivi dans la trace - vous ne pourrez peut-être pas les récupérer dans les événements étendus). La trace par défaut sera récupérez les tables #temp créées avec une PK ou une autre contrainte, ou avec des contraintes ou des index ajoutés après l'événement de création, mais vous devrez ensuite assouplir les restrictions temporelles ci-dessus (un index peut être créé bien plus tard que 100 ms après création).

Quelques autres réponses sur ce site qui peuvent être utiles:

J'ai également blogué à ce sujet, avec une session d'événements étendus personnalisée pour suivre ces informations dans SQL Server 2012 et versions ultérieures:

Et Paul White a blogué sur la lecture de pages directement (pas exactement pour les faibles de cœur, ni facile à automatiser en aucune façon):


5

Voici une requête qui devrait vous aider à découvrir les informations que vous recherchez:

select top 10
    tsu.session_id,
    tsu.request_id,
    r.command,
    s.login_name,
    s.host_name,
    s.program_name,
    total_objects_alloc_page_count = 
        tsu.user_objects_alloc_page_count + tsu.internal_objects_alloc_page_count,
    tsu.user_objects_alloc_page_count,
    tsu.user_objects_dealloc_page_count,
    tsu.internal_objects_alloc_page_count,
    tsu.internal_objects_dealloc_page_count,
    st.text
from sys.dm_db_task_space_usage tsu
inner join sys.dm_exec_requests r
on tsu.session_id = r.session_id
and tsu.request_id = r.request_id
inner join sys.dm_exec_sessions s
on r.session_id = s.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st
where tsu.user_objects_alloc_page_count > 0
or tsu.internal_objects_alloc_page_count > 0
order by total_objects_alloc_page_count desc;

Cette requête extrait des informations utiles pour les 10 principales tâches, telles que les pages allouées / désallouées, le texte SQL des tâches (si disponible), etc.

Ces DMV regorgent d'informations, donc si vous avez besoin de plus de données, vous pouvez mélanger et assortir ce que vous tirez. Mais cela devrait être un point de départ pour le dépannage des tâches de consommation tempdb actuelles.


Merci, ça a l'air plutôt bien. La chose étrange est que si j'exécute un rapport «Utilisation du disque par les meilleures tables» sur le tempdb, la table qui utilise le plus d'espace n'apparaît pas dans le st.text. La table est toujours là après avoir exécuté la requête.
SQLMIKE

1
@SQLMIKE si vous voulez simplement savoir quelle table est la plus grande, vous pouvez l'obtenir auprès de tempdb.sys.dm_db_partition_stats. Malheureusement, vous ne pouvez pas vraiment dire quelle copie de #some_table_nameappartient à quel utilisateur, et vous ne pourrez pas toujours extraire du texte d'instruction qui fait référence à cette table à un moment donné - ce n'est peut-être pas la requête que l'utilisateur exécute actuellement. Vous voudrez peut-être voir ceci et cela
Aaron Bertrand
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.