SQL Server: filtrer la sortie de sp_who2

191

Sous SQL Server, existe-t-il un moyen simple de filtrer la sortie de sp_who2? Disons que je voulais simplement afficher les lignes d'une certaine base de données, par exemple.

Craig Schwarze
la source
2
comme @Nick l'a laissé entendre, les vues de gestion dynamique (DMV) pourraient également valoir la peine d'être examinées.
Mitch Wheat
J'ai ajouté une réponse qui utilise des DMV au lieu de sp_who2
N30

Réponses:

349

Vous pouvez essayer quelque chose comme

DECLARE @Table TABLE(
        SPID INT,
        Status VARCHAR(MAX),
        LOGIN VARCHAR(MAX),
        HostName VARCHAR(MAX),
        BlkBy VARCHAR(MAX),
        DBName VARCHAR(MAX),
        Command VARCHAR(MAX),
        CPUTime INT,
        DiskIO INT,
        LastBatch VARCHAR(MAX),
        ProgramName VARCHAR(MAX),
        SPID_1 INT,
        REQUESTID INT
)

INSERT INTO @Table EXEC sp_who2

SELECT  *
FROM    @Table
WHERE ....

Et filtrez ce dont vous avez besoin.

Adriaan Stander
la source
+1 @ bo-flexson a une belle extension à cette approche.
Lankymart
115

Vous pouvez enregistrer les résultats dans une table temporaire , mais il serait encore mieux d'aller directement à la source sur master.dbo.sysprocesses.

Voici une requête qui retournera presque exactement le même résultat que sp_who2:

SELECT  spid,
        sp.[status],
        loginame [Login],
        hostname, 
        blocked BlkBy,
        sd.name DBName, 
        cmd Command,
        cpu CPUTime,
        physical_io DiskIO,
        last_batch LastBatch,
        [program_name] ProgramName   
FROM master.dbo.sysprocesses sp 
JOIN master.dbo.sysdatabases sd ON sp.dbid = sd.dbid
ORDER BY spid 

Vous pouvez maintenant facilement ajouter les clauses ORDER BYou que WHEREvous souhaitez pour obtenir un résultat significatif.


Vous pouvez également envisager d'utiliser Activity Monitor dans SSMS ( Ctrl+ Alt+ A).

KyleMit
la source
bloqué est différent avec BlkBy. bloqué est la victime qui attend le déverrouillage. BlkBy est un criminel qui se fait verrouiller. Donc, utiliser l'alias BlkBy pour bloquer la colonne est absolument faux. Si sp_who renvoie 1 comme SPID, 2 comme BlkBy, 1 est bloqué par 2.
doctorgu
25

Une façon consiste à créer une table temporaire:

CREATE TABLE #sp_who2 
(
   SPID INT,  
   Status VARCHAR(1000) NULL,  
   Login SYSNAME NULL,  
   HostName SYSNAME NULL,  
   BlkBy SYSNAME NULL,  
   DBName SYSNAME NULL,  
   Command VARCHAR(1000) NULL,  
   CPUTime INT NULL,  
   DiskIO INT NULL,  
   LastBatch VARCHAR(1000) NULL,  
   ProgramName VARCHAR(1000) NULL,  
   SPID2 INT
) 
GO

INSERT INTO #sp_who2
EXEC sp_who2
GO

SELECT *
FROM #sp_who2
WHERE Login = 'bla'
GO

DROP TABLE #sp_who2
GO
Blé Mitch
la source
select * from sp_who2 où login = 'bla' - la table doit-elle faire référence ici par # sp_who2?
Peter Schofield
Obtention de "Le nom de colonne ou le nombre de valeurs fournies ne correspond pas à la définition de la table." exécuter ceci sur SQL 2008 R2
TheLegendaryCopyCoder
11

basé sur http://web.archive.org/web/20080218124946/http://sqlserver2005.databases.aspfaq.com/how-do-i-mimic-sp-who2.html

j'ai créé le script suivant,
qui résout la recherche connexions actives à n'importe quelle base de données utilisant DMV cela fonctionne sous sql 2005, 2008 et 2008R2

Le script suivant utilise sys.dm_exec_sessions , sys.dm_exec_requests , sys.dm_exec_connections , sys.dm_tran_locks

Declare @dbName varchar(1000)
set @dbName='abc'

;WITH DBConn(SPID,[Status],[Login],HostName,DBName,Command,LastBatch,ProgramName)
As
(
SELECT 
    SPID = s.session_id,
    Status = UPPER(COALESCE
        (
            r.status,
            ot.task_state,
            s.status, 
        '')),
    [Login] = s.login_name,
    HostName = COALESCE
        (
            s.[host_name],
            '  .'
        ),
    DBName = COALESCE
        (
            DB_NAME(COALESCE
            (
                r.database_id,
                t.database_id
            )),
            ''
        ),
    Command = COALESCE
        (
            r.Command,
            r.wait_type,
            wt.wait_type,
            r.last_wait_type,
            ''
        ),
    LastBatch = COALESCE
        (
            r.start_time,
            s.last_request_start_time
        ),
    ProgramName = COALESCE
        (
            s.program_name, 
            ''
        )
FROM
    sys.dm_exec_sessions s
LEFT OUTER JOIN
    sys.dm_exec_requests r
ON
    s.session_id = r.session_id
LEFT OUTER JOIN
    sys.dm_exec_connections c
ON
    s.session_id = c.session_id
LEFT OUTER JOIN
(
    SELECT 
        request_session_id,
        database_id = MAX(resource_database_id)
    FROM
        sys.dm_tran_locks
    GROUP BY
        request_session_id
) t
ON
    s.session_id = t.request_session_id
LEFT OUTER JOIN
    sys.dm_os_waiting_tasks wt
ON 
    s.session_id = wt.session_id
LEFT OUTER JOIN
    sys.dm_os_tasks ot
ON 
    s.session_id = ot.session_id
LEFT OUTER JOIN
(
    SELECT
        ot.session_id,
        CPU_Time = MAX(usermode_time)
    FROM
        sys.dm_os_tasks ot
    INNER JOIN
        sys.dm_os_workers ow
    ON
        ot.worker_address = ow.worker_address
    INNER JOIN
        sys.dm_os_threads oth
    ON
        ow.thread_address = oth.thread_address
    GROUP BY
        ot.session_id
) tt
ON
    s.session_id = tt.session_id
WHERE
    COALESCE
    (
        r.command,
        r.wait_type,
        wt.wait_type,
        r.last_wait_type,
        'a'
    ) >= COALESCE
    (
        '', 
        'a'
    )
)

Select * from DBConn
where DBName like '%'+@dbName+'%'
N30
la source
trop compliqué par rapport aux autres réponses. mais mérite un vote positif anw
Doan Cuong
Pas toujours utile par DB, préférez l' approche @astander et @ bo-flexson .
Lankymart
1
Celui-ci montre comment rejoindre le processus du système d'exploitation parent, ce que je voulais.
redcalx
J'ai trouvé que l'utilisation de sys.dm_tran_locks est ce script ralentit massivement ce code si vous avez beaucoup de verrous de transaction ouverts (par exemple une transaction de longue durée).
Mike
6

Légère amélioration de la réponse d' Astander . J'aime mettre mes critères en tête et faciliter la réutilisation au jour le jour:

DECLARE @Spid INT, @Status VARCHAR(MAX), @Login VARCHAR(MAX), @HostName VARCHAR(MAX), @BlkBy VARCHAR(MAX), @DBName VARCHAR(MAX), @Command VARCHAR(MAX), @CPUTime INT, @DiskIO INT, @LastBatch VARCHAR(MAX), @ProgramName VARCHAR(MAX), @SPID_1 INT, @REQUESTID INT

    --SET @SPID = 10
    --SET @Status = 'BACKGROUND'
    --SET @LOGIN = 'sa'
    --SET @HostName = 'MSSQL-1'
    --SET @BlkBy = 0
    --SET @DBName = 'master'
    --SET @Command = 'SELECT INTO'
    --SET @CPUTime = 1000
    --SET @DiskIO = 1000
    --SET @LastBatch = '10/24 10:00:00'
    --SET @ProgramName = 'Microsoft SQL Server Management Studio - Query'
    --SET @SPID_1 = 10
    --SET @REQUESTID = 0

    SET NOCOUNT ON 
    DECLARE @Table TABLE(
            SPID INT,
            Status VARCHAR(MAX),
            LOGIN VARCHAR(MAX),
            HostName VARCHAR(MAX),
            BlkBy VARCHAR(MAX),
            DBName VARCHAR(MAX),
            Command VARCHAR(MAX),
            CPUTime INT,
            DiskIO INT,
            LastBatch VARCHAR(MAX),
            ProgramName VARCHAR(MAX),
            SPID_1 INT,
            REQUESTID INT
    )
    INSERT INTO @Table EXEC sp_who2
    SET NOCOUNT OFF
    SELECT  *
    FROM    @Table
    WHERE
    (@Spid IS NULL OR SPID = @Spid)
    AND (@Status IS NULL OR Status = @Status)
    AND (@Login IS NULL OR Login = @Login)
    AND (@HostName IS NULL OR HostName = @HostName)
    AND (@BlkBy IS NULL OR BlkBy = @BlkBy)
    AND (@DBName IS NULL OR DBName = @DBName)
    AND (@Command IS NULL OR Command = @Command)
    AND (@CPUTime IS NULL OR CPUTime >= @CPUTime)
    AND (@DiskIO IS NULL OR DiskIO >= @DiskIO)
    AND (@LastBatch IS NULL OR LastBatch >= @LastBatch)
    AND (@ProgramName IS NULL OR ProgramName = @ProgramName)
    AND (@SPID_1 IS NULL OR SPID_1 = @SPID_1)
    AND (@REQUESTID IS NULL OR REQUESTID = @REQUESTID)
Bo Flexson
la source
4

Il y a pas mal de bonnes procédures stockées utilisateur sp_who3 - je suis sûr qu'Adam Machanic en a fait une très bonne, AFAIK.

Adam l'appelle qui est actif: http://whoisactive.com

Peter Schofield
la source
J'ai essayé cela, ce n'était pas si facile ... Je publie une autre façon qui est similaire à certains de ces autres articles (mais c'est testé et correct).
Don Rolling
4

Semblable à la réponse de KyleMit , il est possible de sélectionner directement les tables utilisées par SP_WHO2, bien que je pense qu'il ne faut que la table dbo.sysprocesses.

Si quelqu'un ouvre ce SP, il peut comprendre ce qu'il fait. C'est mon meilleur choix pour avoir une sortie similaire à SP_WHO2

select convert(char(5),sp.spid) as SPID
        ,  CASE lower(sp.status)
                 When 'sleeping' Then lower(sp.status)
                 Else  upper(sp.status)
              END as Status
        , convert(sysname, rtrim(sp.loginame)) as LOGIN
        , CASE sp.hostname
                 When Null  Then '  .'
                 When ' ' Then '  .'
                 Else    rtrim(sp.hostname)
              END as HostName
        , CASE isnull(convert(char(5),sp.blocked),'0')
                 When '0' Then '  .'
                 Else isnull(convert(char(5),sp.blocked),'0')
              END as BlkBy
        , case when sp.dbid = 0 then null when sp.dbid <> 0 then db_name(sp.dbid) end as DBName
        , sp.cmd as Command
        , sp.cpu as CPUTime
        , sp.physical_io as DiskIO
        , sp.last_batch as LastBatch
        , sp.program_name as ProgramName 
        from master.dbo.sysprocesses sp (nolock)
  ;

Sur cette sélection, vous pouvez sélectionner les champs dont vous avez besoin et obtenir l'ordre que vous souhaitez.

dchang
la source
A bien fonctionné pour moi
Shai Alon
3

Un moyen très simple de le faire est de créer un lien ODBC dans EXCEL et d'exécuter SP_WHO2 à partir de là.

Vous pouvez actualiser quand vous le souhaitez et parce que c'est EXCEL, tout peut être manipulé facilement!

BM
la source
7
Êtes-vous sûr que c'est le moyen le plus simple?
geomagas
2

Oui, en capturant la sortie de sp_who2 dans une table puis en sélectionnant dans la table, mais ce serait une mauvaise façon de le faire. Premièrement, parce que sp_who2, malgré sa popularité, est une procédure non documentée et vous ne devriez pas vous fier à des procédures non documentées. Deuxièmement, parce que tout ce que sp_who2 peut faire, et bien plus encore, peut être obtenu à partir de sys.dm_exec_requests et d'autres DMV, et que le spectacle peut être filtré, ordonné, joint et tous les autres bonus fournis avec les ensembles de lignes interrogeables.

Remus Rusanu
la source
4
Ceci est un cas où je ne serais pas utiliser un DMV connect.microsoft.com/SQLServer/feedback/details/257502/...
GBN
1

Extension de la première et meilleure réponse ... J'ai créé une procédure stockée sur la base de données master à laquelle vous pouvez ensuite passer des paramètres .. comme le nom de la base de données:

USE master
GO

CREATE PROCEDURE sp_who_db
(
    @sDBName varchar(200)   = null,
    @sStatus varchar(200)   = null,
    @sCommand varchar(200)  = null,
    @nCPUTime int           = null
)
AS
DECLARE @Table TABLE
(
    SPID INT,
    Status VARCHAR(MAX),
    LOGIN VARCHAR(MAX),
    HostName VARCHAR(MAX),
    BlkBy VARCHAR(MAX),
    DBName VARCHAR(MAX),
    Command VARCHAR(MAX),
    CPUTime INT,
    DiskIO INT,
    LastBatch VARCHAR(MAX),
    ProgramName VARCHAR(MAX),
    SPID_1 INT,
    REQUESTID INT
)

INSERT INTO @Table EXEC sp_who2

SELECT  *
    FROM    @Table
    WHERE   (@sDBName IS NULL OR DBName = @sDBName)
    AND     (@sStatus IS NULL OR Status = @sStatus)
    AND     (@sCommand IS NULL OR Command = @sCommand)
    AND     (@nCPUTime IS NULL OR CPUTime > @nCPUTime)
GO 

Je pourrais l'étendre pour ajouter un ordre par paramètre ou même un paramètre kill afin qu'il tue toutes les connexions à une donnée particulière

Jon Bosker
la source
0

J'écris ici pour mon usage futur. Il utilise sp_who2 et s'insère dans la variable de table au lieu de la table temporaire car la table Temp ne peut pas être utilisée deux fois si vous ne la supprimez pas. Et montre bloqué et bloqueur sur la même ligne.

--blocked: waiting becaused blocked by blocker
--blocker: caused blocking
declare @sp_who2 table(
    SPID int,
    Status varchar(max),
    Login varchar(max),
    HostName varchar(max),
    BlkBy varchar(max),
    DBName varchar(max),
    Command varchar(max),
    CPUTime int,
    DiskIO int,
    LastBatch varchar(max),
    ProgramName varchar(max),
    SPID_2 int,
    REQUESTID int
)
insert into @sp_who2 exec sp_who2
select  w.SPID blocked_spid, w.BlkBy blocker_spid, tblocked.text blocked_text, tblocker.text blocker_text
from    @sp_who2 w
        inner join sys.sysprocesses pblocked on w.SPID = pblocked.spid
        cross apply sys.dm_exec_sql_text(pblocked.sql_handle) tblocked
        inner join sys.sysprocesses pblocker on case when w.BlkBy = '  .' then 0 else cast(w.BlkBy as int) end = pblocker.spid
        cross apply sys.dm_exec_sql_text(pblocker.sql_handle) tblocker
where   pblocked.Status = 'SUSPENDED'
doctorgu
la source