Descubrir bloqueos en SQL Server
Posted by Miguel Egea | Posted in Relacional | Posted on 08-01-2010
9
Los bloqueos son la principal causa de bajo rendimiento inexplicable, y generalmente son muy complicados de cazar, de detectar y de solucionar, hablaremos de bloqueos más adelante, pero ahora mismo vamos a poner un procedimiento almacenado que sirve para cazar a los procesos bloqueadores y pondremos una imagen en la que se ve cual es el resultado, en proximos capÃtulos pondremos como configurar el SQL Mail para que además nos lleguen por correo electrónico
*/ CREATE PROC CazaBloqueadores @waittime varchar(10) as begin begin try declare @t table (bloqueado int, bloqueador int) -- usaremos la variable de tipo tabla para esperar insert into @t (bloqueado,bloqueador) select session_id, blocking_session_id from sys.dm_exec_requests der where blocking_session_id!=0 -- Recogemos los objetos que están bloqueados.. waitfor delay @waittime SELECT der.session_id [Sesion bloqueada], det.text [Comando Bloqueado], der.[blocking_Session_id] [id del bloqueador], subq.TEXT [Comando Bloqueador], des.[host_name] [Nombre del host], des.[Program_name] [Aplicación], db_name(der.database_id) [Base de Datos], user_name(der.user_id) [usuario de bbdd], des.login_name [login], cast(des.context_info as varchar(100)) [Informacion Adicional], des.cpu_time [Tiempo de CPU], des.total_elapsed_time [Tiempo de espera], des.logical_reads [lecturas], des.writes [escrituras], der.start_time [Comenzó], der.status [estado], case des.transaction_isolation_level when 0 then 'Sin especificar' when 1 then 'Read Uncommitted' when 2 then 'Read Committed' when 3 then 'Repeatable reads' when 4 then 'Serializable' when 5 then 'Snapshot' else 'Inesperado' end [Nivel de Aislamiento] FROM sys.dm_exec_requests der INNER JOIN sys.dm_exec_sessions des ON der.session_id=des.session_id CROSS APPLY sys.dm_exec_sql_text(sql_handle) det LEFT JOIN (select SPID session_id, det2.[text] from sys.sysprocesses der2 CROSS APPLY sys.dm_exec_sql_text(sql_handle) det2 ) subq ON der.[blocking_Session_id]=subq.session_id WHERE der.blocking_session_id in (select bloqueador from @t) return 0 end try begin catch declare @error sysname set @error=ERROR_MESSAGE() raiserror (@error,16,1) return 1 end catch end |
y esta la versión para SQL 2000
-- *************************************************************************** -- Copyright (C) PortalSQL 2006 -- -- Fichero: CazaBloqueadores.sql -- Descr.: Busca bloqueos que se mantengan -- durante el tiempo que le pasemos por parámetro, si hay bloqueos que se mantienen -- muestra información relevante -- autor: Miguel Egea Gómez -- Solid Quality Learning IberoAmericana -- -- comentarios: Puede ser adecuado meter ejecutar este procedimiento desde un job y -- usar DatabaseMail para reportar sus resultados al administrador de base -- de datos. -- He usado la vista de compatibilidad sys.sysprocesses, esto es porque he c -- comprobado que algunas ocasiones la tabla sys.dm_exec_request no tiene registros -- para los bloqueadores. -- -- Parámetros de entrada: -- @waittime --> Tiempo que debe esperarse para considerar que hay un bloqueo -- Valores de retorno : 0--> Funcionó de forma correcta -- 1--> En cualquir otro caso -- -- <!--(más reciente más arriba) --> -- yyyy/mm/dd by description -- ========== ======= ========================================================== -- 2006/06/04 MEG Creación. -- -- *************************************************************************** -- Ejemplo de llamada -- /* DECLARE @Valor varchar(10) ,@result int SET @Valor='00:00:02' EXEC @result =CazaBloqueadores @valor select @result |
Aquà puedes ver una imagen en la que se ejecuta un comando que genera un bloqueo, y un comando que se ve bloqueado por ese bloqueo, cuando se crea una tabla dentro de una transacción se genera un bloqueo, un select que consulte esa tabla espera a que se haga commit o rollback en la creación, para devolver los registros o un error.Â
a continuación puedes ver más resultados devueltos por el procedimiento almacenado
Disfruta del código
Modificado para incluir Versión SQL Server 2000 en marzo de 2011
Si buscas un código equivalente, pero para SQL Server 2000, este podrÃa estar bien
Â
create procedure cazabloqueos2000 as begin create table #bloqueos(spidbloqueador int,hostnamebloqueador sysname,loginamebloqueador sysname, spidbloqueado int,hostnamebloqueado sysname,loginamebloqueado sysname) insert into #bloqueos select a.spid,a.hostname,a.loginame,b.spid,b.hostname,b.loginame From ( select * from sysprocesses where blocked!=0) a inner join master.sys.sysprocesses b on a.blocked=b.spid declare @spid int alter table #bloqueos add sentenciabloqueador varchar(8000); alter table #bloqueos add sentenciabloqueado varchar(8000); declare cr cursor for select distinct spidbloqueador from #bloqueos open cr fetch next from cr into @spid create table #temp (eventtype varchar(100),paremeters varchar(100),eventinfo varchar(8000) ) declare @sql nvarchar(1000) while (@@FETCH_STATUS=0) begin select @sql='dbcc inputbuffer(' +cast(@spid as varchar(10)) +')' insert into #temp exec(@sql) update b set sentenciabloqueador=eventinfo from #bloqueos b cross join #temp where b.spidbloqueador=@spid delete from #temp fetch next from cr into @spid end close cr deallocate cr declare cr cursor for select distinct spidbloqueado from #bloqueos open cr fetch next from cr into @spid while (@@FETCH_STATUS=0) begin select @sql='dbcc inputbuffer(' +cast(@spid as varchar(10)) +')' insert into #temp exec(@sql) update b set sentenciabloqueado=eventinfo from #bloqueos b cross join #temp where b.spidbloqueado=@spid delete from #temp fetch next from cr into @spid end close cr deallocate cr select * From #bloqueos end |



Un consejo, instalate el plugin codebox para que sea mas entendible para todos nosotros tu codigo
Lo dicho eres una p… máquina. InteresantÃsimo como todos tus artÃculos. Por cierto, haber cuando nos deleitas con uno dedicado a directivas, ya sabes, por pedir que no quede
Nos vemos ….
Instalado el plugging, realmente instalado por segunda vez, porque lo instalé la primera y algo debió subirse mal, pensé que no funcionaba ya hora… me parece una maravilla, gracias GeekZero
Muchas gracias por el aporte. Espero que me sea de utilidad en algún momento, que seguro que asà será.
Un saludo
M sale error “sql_handle” no es una opción reconocida de sugerencias de tabla. Si se debe usar como un parámetro en una función con valores de tabla, asegúrese de que el modo de compatibilidad de la base de datos está establecido en 90.
Tengo sql2008,,
Efectivaamente Rafael, esto solo funciona en bases de datos SQL 2005 y adelante, es decir nivel de compatibilidad 90 y adelante. Para compatibilidad 2000 hay que usar dbcc inputbuffer.
Miguel, me interesa mucho tu proceso, pero me pasa lo mismo que a Rafael, pero no se como colocar el dbcc inputbuffer, me puedes ayudar por favor, Gracias
Incluida versión para SQL Server 2000, espero que resulte útlil. y que funcione, porque lo hice en un 2008 intentando acordarme de la sintaxis
Hola Miguel, el codigo me resulta muy util, me has salvado.
Una pregunta, lo quiero meter en un job, pero no quiero afectar mas el performance del servidor. Que frecuencia recomiendas para que se ejecute el job sin darle sobrecarga al servidor?