为什么sp_who2没有根据`@ loginame`参数过滤结果?

时间:2014-03-21 13:44:59

标签: sql sql-server-2012

我没有像下面的问题那样引用过滤sp_who2 SQL Server: Filter output of sp_who2而是关于使用@loginame参数仅为特定用户获取结果。

例如:

EXEC sp_who @loginame = 'sa' 

EXEC sp_who2 @loginame = 'sa' 

使用sp_who参数运行@loginame时,结果仅会过滤给特定用户,但该行为不在sp_who2中。

2 个答案:

答案 0 :(得分:3)

基于此处的连接项目

http://connect.microsoft.com/SQLServer/feedback/details/264681/sp-who2-provide-supported-documented-version

在这里

https://connect.microsoft.com/SQLServer/feedback/details/207997/remove-reference-to-undocumented-sp-who2-from-books-online

我将建议您使用未记录的功能“由您自行承担风险”,因为结果无法保证,可能会或可能不会在将来的版本中使用 没有太多警告。 此外,可能存在与未解决的代码相关的错误。最后,正如您所提到的,我曾经知道使用sp_who2的唯一过滤器是过滤“活动”连接。这就是我使用DMV检查活动连接的原因。

如果无法将存储过程部署到您的环境,则还可以运行以下代码。应该注意的是,它是非常重量级的并且将产生“倍数”会话,因为它拉动与每个会话id相关联的子任务(执行上下文)。另外,如果你有一个执行上下文命中tempdb和用户db,它会进一步复制它。

SELECT          
        instance_name = @@SERVERNAME,
        GETDATE() AS collection_date,
        s.session_id,
        r.request_id,
        DB_NAME(r.database_id) as request_database_name,
        r.command,
        w.exec_context_id,
        w.blocking_session_id,
        w.blocking_exec_context_id,
        s.login_time, 
        s.host_name, 
        s.program_name, 
        s.client_interface_name,
        s.login_name,
        s.cpu_time AS session_cpu_time,
        r.cpu_time AS request_cpu_time ,
        s.memory_usage, 
        s.total_scheduled_time, 
        s.total_elapsed_time, 
        s.last_request_start_time, 
        s.last_request_end_time, 
        request_start_time = r.start_time,
        s.reads as session_reads, 
        r.reads AS request_reads,
        s.logical_reads AS session_logical_reads , 
        r.logical_reads as request_logical_reads ,
        s.writes as session_writes,
        r.writes AS request_writes ,
        r.wait_type AS request_wait_type , 
        r.wait_time AS request_wait_time , 
        w.wait_type AS waiting_tasks_wait_type , 
        w.wait_duration_ms AS waiting_tasks_wait_duration,        
            SUBSTRING(qt.text,r.statement_start_offset/2,  
            (case when r.statement_end_offset = -1  
            then len(convert(nvarchar(max), qt.text)) * 2  
            else r.statement_end_offset end -r.statement_start_offset)/2) as request_query_text, 
        CAST(qp.query_plan as XML) AS query_plan,
        r.sql_handle AS request_sql_handle , 
        r.plan_handle AS request_plan_handle,
        w.resource_description,
        t.transaction_id,
        t.name, 
        t.transaction_begin_time, 
        t.transaction_type, 
        t.transaction_state,
        t.database_transaction_log_record_count,
        t.database_transaction_log_bytes_used,
        t.database_transaction_log_bytes_reserved,
        t.database_id,
        t.database_transaction_state, 
        t.enlist_count, 
        t.is_user_transaction, 
        t.transaction_descriptor,
        (SELECT     
                    lock.resource_type AS resource_type, 
                    lock.resource_subtype AS resource_subtype, 
                    LTRIM(RTRIM(lock.resource_description)) AS resource_description,
                    lock.resource_database_id AS resource_database_id,
                    lock.resource_associated_entity_id AS resource_database_entity_id, 
                    lock.resource_lock_partition AS resource_lock_partition,
                    lock.request_mode AS request_mode, 
                    lock.request_type AS request_type, 
                    lock.request_status AS request_status,
                    lock.request_exec_context_id as request_context_id, 
                    DB_NAME(lock.resource_database_id) AS resource_database_name
                    FROM sys.dm_tran_locks lock 
                        WHERE lock.request_session_id = r.session_id
                        AND lock.request_exec_context_id = w.exec_context_id
                FOR XML AUTO, TYPE, ROOT('locks'))
                AS locks,
        tu.user_objects_alloc_page_count, 
        tu.user_objects_dealloc_page_count, 
        tu.internal_objects_alloc_page_count, 
        tu.internal_objects_dealloc_page_count  
FROM sys.dm_exec_sessions s
JOIN sys.dm_exec_requests r 
    ON s.session_id = r.session_id
LEFT JOIN sys.dm_os_waiting_tasks w
    ON s.session_id = w.session_id
LEFT JOIN (
            SELECT 
                DISTINCT
                at.transaction_id,
                at.name, 
                at.transaction_begin_time, 
                at.transaction_type, 
                at.transaction_state,
                dt.database_transaction_log_record_count,
                dt.database_transaction_log_bytes_used,
                dt.database_transaction_log_bytes_reserved,
                dt.database_id,
                dt.database_transaction_state, 
                st.enlist_count, 
                st.is_user_transaction, 
                st.transaction_descriptor
            FROM sys.dm_tran_active_transactions at
                JOIN sys.dm_tran_database_transactions dt
                    ON at.transaction_id = dt.transaction_id
                LEFT JOIN sys.dm_tran_session_transactions st
                    ON st.transaction_id = at.transaction_id
    ) t
    ON t.transaction_id = r.transaction_id
LEFT JOIN sys.dm_db_task_space_usage  tu
    ON tu.exec_context_id = w.exec_context_id
    AND tu.session_id = s.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) as qt 
OUTER APPLY sys.dm_exec_query_plan(r.plan_handle) AS qp
WHERE r.session_id > 50 AND r.session_id != @@SPID
 -- AND s.login_name = 'sa'

答案 1 :(得分:2)

在挖掘sp_who2代码后,我发现了这个错误。所以解释很简单。

有4个参数

DECLARE @sidlow VARBINARY(85)
   ,@sidhigh VARBINARY(85)
   ,@sid1 VARBINARY(85)
   ,@spidlow INT
   ,@spidhigh INT

他们默认为以下

SELECT @sidlow = CONVERT(VARBINARY(85), ( REPLICATE(CHAR(0), 85) ))
SELECT @sidhigh = CONVERT(VARBINARY(85), ( REPLICATE(CHAR(1), 85) ))

SELECT @spidlow = 0, @spidhigh = 32767

,如果您传入@loginame参数@sidlow@sidhigh会在以下声明中更新。

IF ( @sid1 IS NOT NULL )  --Parm is a recognized login name.
    BEGIN
        SELECT @sidlow = SUSER_SID(@loginame)
               ,@sidhigh = SUSER_SID(@loginame)
        GOTO LABEL_17PARM1EDITED
    END

但是一旦你到达SP的底部,假设它返回@sidlow@sidhigh,则执行以下代码。

SELECT @charMaxLenLoginName = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(loginname)), 5))
       ,@charMaxLenDBName = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), DB_NAME(dbid))))), 6))
       ,@charMaxLenCPUTime = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), cpu)))), 7))
       ,@charMaxLenDiskIO = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), physical_io)))), 6))
       ,@charMaxLenCommand = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), cmd)))), 7))
       ,@charMaxLenHostName = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), hostname)))), 8))
       ,@charMaxLenProgramName = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), program_name)))),
                                                         11))
       ,@charMaxLenLastBatch = CONVERT(VARCHAR, ISNULL(MAX(DATALENGTH(RTRIM(CONVERT(VARCHAR(128), last_batch_char)))),
                                                       9))
    FROM #tb1_sysprocesses
    WHERE spid >= @spidlow
        AND spid <= @spidhigh

正如您所看到的那样@sidlow@sidhigh正在使用@spidlow@spidhigh这些从未更改的内容。因此,您仍然可以获得所有记录。

现在传递的内容是'active'

EXEC sp_who2 @loginame = 'sa' 

EXEC sp_who2 @loginame = 'active' 

第一个将返回前面讨论的所有行,但第二个执行只会返回活动行,因为以下代码

--------Screen out any rows?

IF ( @loginame IN ( 'active' ) )
    DELETE #tb1_sysprocesses
        WHERE LOWER(status) = 'sleeping'
            AND UPPER(cmd) IN ( 'AWAITING COMMAND', 'LAZY WRITER', 'CHECKPOINT SLEEP' )
            AND blocked = 0

此代码删除临时表#tb1_sysprocesses中将用于返回的所有“非活动”记录。


<强>结论

这个SP就像在@swasheck提供的链接中提到的那样被窃听,并且根据微软的回复,他们不会修复它。他们建议使用DMV而不是这个。

为程序提供有效的登录名不会修改结果。

EXEC sp_who2 @loginame = 'sa' --All Rows returned

向程序提供'Active'会将结果仅过滤到“活动”记录。

EXEC sp_who2 @loginame = 'active' --Only Active SIDs returned