SQLテーブルがあり、with (nolock)
を最後に含めない限り、突然データを返すことができません。これは、テーブルに何らかのロックが残っていることを示しています。
sys.dm_tran_locks で少し実験して、テーブルに実際に多数のロックがあることを特定しましたが、どのように特定するのですかwhatそれらをロックしています(つまり、 sys.dm_tran_locks )のリクエスト要素ですか?
編集:私は sp_lock SQL 2005以前について知っていますが、そのspは非推奨になったので、これを行う正しい方法は sys.dm_tran_locks を使用することです。 SQL Server 2008 R2を使用しています。
SQLServer Management Studio(SSMS)で実行できる次のシステムストアドプロシージャを見てください。
また、SSMSでは、さまざまな方法でロックとプロセスを表示できます。
SSMSの異なるバージョンは、アクティビティモニターを異なる場所に配置します。たとえば、SSMS 2008および2012では、サーバーノードを右クリックしたときにコンテキストメニューに表示されます。
「誰がブロックされているか/ブロックされているか」を理解するために、sp_whoとsp_lockを1つのクエリに結合/短縮して、どのオブジェクトがどのレベルにロックされているかを簡単に説明します。
--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
(ロックレベルの略語の意味については、たとえば https://technet.Microsoft.com/en-us/library/ms175519%28v=sql.105%29.aspx を参照してください)
コピー元: sp_WhoLock – sp_whoとsp_lockを組み合わせたT-SQLストアドプロシージャ...
NB [コマンドの排他ロック]列は誤解を招く可能性があります-そのspidの現在のコマンドが表示されます。ただし、トランザクション内の以前のコマンドによってXロックがトリガーされた可能性があります。
私は、ロックとブロックだけでなく、サーバーで実行されているものを確認するためのストアドプロシージャを作成しました。マスターに入れました。コードを以下に示します。
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
この手順は、ここ数年で非常に役立っています。実行するには、sp_radheと入力します。
masterデータベースにsp_radheを置くことについて
次のコードを使用して、システムストアドプロシージャにします
exec sys.sp_MS_marksystemobject 'sp_radhe'
下のリンクをご覧ください
独自のSQL Serverシステムストアドプロシージャの作成
トランザクション分離レベルについて
質問するのが面倒だったT-SQLトランザクション分離レベルに関する質問
トランザクション分離レベルを変更すると、プロシージャまたはリターンコールの終了時にスコープが終了したとき、またはSET TRANSACTION ISOLATION LEVELを使用して明示的に再度変更したときにのみ変更されます。
さらに、TRANSACTION ISOLATION LEVELはストアドプロシージャのみを対象としているため、独自の特定の分離レベルで実行される複数のネストされたストアドプロシージャを持つことができます。
exec sp_lock
このクエリは、既存のロックを提供します。
exec sp_who SPID -- will give you some info
Spidがある場合、アクティビティモニター([プロセス]タブ)をチェックして、テーブルをロックしているプロセスを確認できます(詳細については「詳細」、それを強制終了するには「プロセスを強制終了」)。
sp_who2
を使用して、詳細情報を提供することもできます
ここにいくつかの情報があります http://dbadiaries.com/using-sp_who2-to-help-with-sql-server-troubleshooting
プロットツイスト!
排他ロックを保持している孤立した分散トランザクションを持つことができ、スクリプトがトランザクションに関連付けられたセッションがあると想定する場合、それらは表示されません(ありません!)。以下のスクリプトを実行して、これらのトランザクションを識別します。
;WITH ORPHANED_TRAN AS (
SELECT
dat.name,
dat.transaction_uow,
ddt.database_transaction_begin_time,
ddt.database_transaction_log_bytes_reserved,
ddt.database_transaction_log_bytes_used
FROM
sys.dm_tran_database_transactions ddt,
sys.dm_tran_active_transactions dat,
sys.dm_tran_locks dtl
WHERE
ddt.transaction_id = dat.transaction_id AND
dat.transaction_id = dtl.request_owner_id AND
dtl.request_session_id = -2 AND
dtl.request_mode = 'X'
)
SELECT DISTINCT * FROM ORPHANED_TRAN
トランザクションを特定したら、transaction_uow列を使用してMSDTCでそれを見つけ、中止するかコミットするかを決定します。トランザクションが「疑わしい」とマークされている場合(横に疑問符が付いている場合)、おそらく中止する必要があります。
KILLコマンドでtransaction_uowを指定して、作業単位(UOW)を強制終了することもできます。
KILL '<transaction_uow>'
参照:
https://www.mssqltips.com/sqlservertip/4142/how-to-kill-a-blocking-negative-spid-in-sql-server/
公式ドキュメントによると、 sp_lock は非推奨としてマークされています:
この機能はメンテナンスモードであり、Microsoft SQL Serverの将来のバージョンでは削除される可能性があります。新しい開発作業でこの機能を使用することは避け、現在この機能を使用しているアプリケーションの変更を計画してください。
代わりに sys.dm_tran_locks を使用することをお勧めします。この動的管理オブジェクトは、現在アクティブなロックマネージャーリソースに関する情報を返します。各行は、許可されているか、許可を待っているロックに対するロックマネージャへの現在アクティブな要求を表します。
一般に、sp_lock
が行うよりもユーザーフレンドリーな構文で詳細を返します。
whoisactive によって書かれた Adam Machanic ルーチンは、環境内の現在のアクティビティを確認し、どのタイプの待機/ロックがクエリを遅らせているかを確認するのに非常に適しています。クエリやその他の便利な情報をブロックしているものを簡単に見つけることができます。
たとえば、次のクエリが既定のSQL Server分離レベル-コミット済みで実行されているとします。各クエリは個別のクエリウィンドウで実行されます。
-- 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];
次にsp_whoisactive
を実行します(列の一部のみが表示されます)。
SELECT
ステートメントとそのT-SQLコードをブロックしているセッションを簡単に確認できます。ルーチンには多くのパラメーターがあるため、詳細については docs を確認してください。
sys.dm_tran_locks
ビューをクエリすると、セッションの1つが他のセッションによる排他ロックを持っているリソースの共有ロックを待っていることがわかります。
これにより、既存のロックの詳細がすべて表示されます。どこかからクロスアプライパーツを入手しましたが、どこにあるか忘れていました。同様の投稿に気づいたら、この回答を編集してリンクを追加してください。ありがとうございました。
DECLARE @tblVariable TABLE(SPID INT, Status VARCHAR(200), [Login] VARCHAR(200), HostName VARCHAR(200),
BlkBy VARCHAR(200), DBName VARCHAR(200), Command VARCHAR(200), CPUTime INT,
DiskIO INT, LastBatch VARCHAR(200), ProgramName VARCHAR(200), _SPID INT,
RequestID INT)
INSERT INTO @tblVariable
EXEC Master.dbo.sp_who2
SELECT v.*, t.TEXT
FROM @tblVariable v
INNER JOIN sys.sysprocesses sp ON sp.spid = v.SPID
CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) AS t
ORDER BY BlkBy DESC, CPUTime DESC
その後、注意して、テーブルをブロックするSPIDを強制終了できます。
kill 104 -- Your SPID