J'ai une table SQL qui ne peut tout à coup renvoyer de données à moins d'inclure "with (nolock)" à la fin, ce qui indique une sorte de verrou laissé sur ma table. J'ai un peu expérimenté avec dm_tran_locks pour identifier qu'il y avait en fait un certain nombre de verrous sur la table, mais comment puis-je identifier quoi les verrouille (c'est-à-dire l'élément request de dm_tran_locks)?
EDIT: Je connais sp_lock pour les versions antérieures à SQL 2005, mais maintenant que sp est obsolète, autant que je sache, c'est avec dm_tran_locks. J'utilise SQL Server 2008 R2.
Examinez les procédures stockées système suivantes, que vous pouvez exécuter dans SQLServer Management Studio (SSMS):
En outre, dans SSMS, vous pouvez afficher les verrous et les processus de différentes manières:
Différentes versions de SSMS placent le moniteur d'activité à différents endroits. Par exemple, SSMS 2008 et 2012 l'ont dans le menu contextuel lorsque vous cliquez avec le bouton droit sur un nœud de serveur.
Pour aller directement à "qui est bloqué/bloqué", j'ai combiné/abrégé sp_who et sp_lock en une seule requête qui donne une bonne vue d'ensemble de qui a quel objet est verrouillé à quel niveau.
--Create Procedure WhoLock
--AS
set nocount on
if object_id('tempdb..#locksummary') is not null Drop table #locksummary
if object_id('tempdb..#lock') is not null Drop table #lock
create table #lock ( spid int, dbid int, objId int, indId int, Type char(4), resource nchar(32), Mode char(8), status char(6))
Insert into #lock exec sp_lock
if object_id('tempdb..#who') is not null Drop table #who
create table #who ( spid int, ecid int, status char(30),
loginame char(128), hostname char(128),
blk char(5), dbname char(128), cmd char(16)
--
, request_id INT --Needed for SQL 2008 onwards
--
)
Insert into #who exec sp_who
Print '-----------------------------------------'
Print 'Lock Summary for ' + @@servername + ' (excluding tempdb):'
Print '-----------------------------------------' + Char(10)
Select left(loginame, 28) as loginame,
left(db_name(dbid),128) as DB,
left(object_name(objID),30) as object,
max(mode) as [ToLevel],
Count(*) as [How Many],
Max(Case When mode= 'X' Then cmd Else null End) as [Xclusive lock for command],
l.spid, hostname
into #LockSummary
from #lock l join #who w on l.spid= w.spid
where dbID != db_id('tempdb') and l.status='GRANT'
group by dbID, objID, l.spid, hostname, loginame
Select * from #LockSummary order by [ToLevel] Desc, [How Many] Desc, loginame, DB, object
Print '--------'
Print 'Who is blocking:'
Print '--------' + char(10)
SELECT p.spid
,convert(char(12), d.name) db_name
, program_name
, p.loginame
, convert(char(12), hostname) hostname
, cmd
, p.status
, p.blocked
, login_time
, last_batch
, p.spid
FROM master..sysprocesses p
JOIN master..sysdatabases d ON p.dbid = d.dbid
WHERE EXISTS ( SELECT 1
FROM master..sysprocesses p2
WHERE p2.blocked = p.spid )
Print '--------'
Print 'Details:'
Print '--------' + char(10)
Select left(loginame, 30) as loginame, l.spid,
left(db_name(dbid),15) as DB,
left(object_name(objID),40) as object,
mode ,
blk,
l.status
from #lock l join #who w on l.spid= w.spid
where dbID != db_id('tempdb') and blk <>0
Order by mode desc, blk, loginame, dbID, objID, l.status
(Pour connaître la signification des abréviations du niveau de verrouillage, voir par exemple https://technet.Microsoft.com/en-us/library/ms175519%28v=sql.105%29.aspx )
Copié à partir de: sp_WhoLock - un proc stocké T-SQL combinant sp_who et sp_lock ...
NB: la colonne [Verrou exclusif pour la commande] peut être trompeuse - elle indique la commande en cours pour ce spid; mais le verrou X aurait pu être déclenché par une commande antérieure de la transaction.
J'ai mis en place une procédure stockée qui traite non seulement des verrous et des blocages, mais aussi de voir ce qui est exécuté sur un serveur . , le code est ci-dessous:
USE [master]
go
CREATE PROCEDURE [dbo].[sp_radhe]
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
-- the current_processes
-- marcelo miorelli
-- CCHQ
-- 04 MAR 2013 Wednesday
SELECT es.session_id AS session_id
,COALESCE(es.original_login_name, '') AS login_name
,COALESCE(es.Host_name,'') AS hostname
,COALESCE(es.last_request_end_time,es.last_request_start_time) AS last_batch
,es.status
,COALESCE(er.blocking_session_id,0) AS blocked_by
,COALESCE(er.wait_type,'MISCELLANEOUS') AS waittype
,COALESCE(er.wait_time,0) AS waittime
,COALESCE(er.last_wait_type,'MISCELLANEOUS') AS lastwaittype
,COALESCE(er.wait_resource,'') AS waitresource
,coalesce(db_name(er.database_id),'No Info') as dbid
,COALESCE(er.command,'AWAITING COMMAND') AS cmd
,sql_text=st.text
,transaction_isolation =
CASE es.transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
END
,COALESCE(es.cpu_time,0)
+ COALESCE(er.cpu_time,0) AS cpu
,COALESCE(es.reads,0)
+ COALESCE(es.writes,0)
+ COALESCE(er.reads,0)
+ COALESCE(er.writes,0) AS physical_io
,COALESCE(er.open_transaction_count,-1) AS open_tran
,COALESCE(es.program_name,'') AS program_name
,es.login_time
FROM sys.dm_exec_sessions es
LEFT OUTER JOIN sys.dm_exec_connections ec ON es.session_id = ec.session_id
LEFT OUTER JOIN sys.dm_exec_requests er ON es.session_id = er.session_id
LEFT OUTER JOIN sys.server_principals sp ON es.security_id = sp.sid
LEFT OUTER JOIN sys.dm_os_tasks ota ON es.session_id = ota.session_id
LEFT OUTER JOIN sys.dm_os_threads oth ON ota.worker_address = oth.worker_address
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS st
where es.is_user_process = 1
and es.session_id <> @@spid
and es.status = 'running'
ORDER BY es.session_id
end
GO
cette procédure a très bien fonctionné pour moi ces dernières années . pour l'exécuter, tapez simplement sp_radhe
Concernant l'insertion de sp_radhe dans la base de données master
J'utilise le code suivant et en fais un procédure stockée système
exec sys.sp_MS_marksystemobject 'sp_radhe'
comme vous pouvez le voir sur le lien ci-dessous
Création de vos propres procédures stockées système SQL Server
Concernant le niveau d'isolation de la transaction
Questions sur les niveaux d'isolement des transactions T-SQL pour lesquelles vous étiez trop timide
Une fois que vous avez modifié le niveau d'isolation de transaction, il ne change que lorsque l'étendue se termine à la fin de la procédure ou d'un appel de retour, ou si vous le modifiez à nouveau de manière explicite à l'aide de SET TRANSACTION ISOLATION LEVEL.
De plus, le NIVEAU TRANSACTION D'ISOLEMENT est limité au procédure stockée, vous pouvez donc avoir plusieurs procédures stockées imbriquées qui s'exécutent à leurs propres niveaux d'isolement.
exec sp_lock
Cette requête devrait vous donner des verrous existants.
exec sp_who SPID -- will give you some info
Ayant des spids, vous pouvez consulter le moniteur d'activité (onglet des processus) pour savoir quels processus verrouillent les tables ("détails" pour plus d'informations et "kill processus" pour le tuer).
Vous pouvez également utiliser sp_who2
qui donne plus d'informations
Voici quelques informations http://dbadiaries.com/using-sp_who2-to-help-with-sql-server-troubleshooting
Selon la documentation officielle, sp_lock est considéré comme obsolète:
Cette fonctionnalité est en mode maintenance et pourra être supprimée ultérieurement version de Microsoft SQL Server. Évitez d’utiliser cette fonctionnalité dans le nouveau fichier travaux de développement et envisagez de modifier les applications qui utilisent actuellement cette fonctionnalité.
et il est recommandé d'utiliser sys.dm_tran_locks à la place. Cet objet de gestion dynamique renvoie des informations sur les ressources du gestionnaire de verrouillage actuellement actives. Chaque ligne représente une demande active au gestionnaire de verrous pour un verrou qui a été accordé ou est en attente de l'être.
Il retourne généralement plus de détails dans une syntaxe plus conviviale que sp_lock
.
La routine whoisactive écrite par Adam Machanic est très utile pour vérifier l'activité en cours dans votre environnement et voir quels types d'attentes/verrous ralentissent vos requêtes. Vous pouvez très facilement trouver ce qui bloque vos requêtes et de nombreuses autres informations utiles.
Par exemple, supposons que les requêtes suivantes soient exécutées dans le niveau d'isolation par défaut de SQL Server - Lecture validée. Chaque requête s'exécute dans une fenêtre de requête distincte:
-- creating sample data
CREATE TABLE [dbo].[DataSource]
(
[RowID] INT PRIMARY KEY
,[RowValue] VARCHAR(12)
);
INSERT INTO [dbo].[DataSource]([RowID], [RowValue])
VALUES (1, 'samle data');
-- query window 1
BEGIN TRANSACTION;
UPDATE [dbo].[DataSource]
SET [RowValue] = 'new data'
WHERE [RowID] = 1;
--COMMIT TRANSACTION;
-- query window 2
SELECT *
FROM [dbo].[DataSource];
Puis exécutez le sp_whoisactive
(seule une partie des colonnes est affichée):
Vous pouvez facilement voir la session qui bloque l'instruction SELECT
et même son code T-SQL. La routine a beaucoup de paramètres, vous pouvez donc vérifier le docs pour plus de détails.
Si nous interrogeons la vue sys.dm_tran_locks
, nous pouvons voir que l'une des sessions attend le verrouillage de partage d'une ressource, qui dispose d'un verrouillage exclusif par une autre session: