為什麼資料庫有時候不能定位阻塞(Blocker)源頭的SQL語句

来源:http://www.cnblogs.com/kerrycode/archive/2016/08/30/5821413.html
-Advertisement-
Play Games

在SQL Server資料庫或OACLE資料庫當中,通常一個會話持有某個資源的鎖,而另一個會話在請求這個資源,就會出現阻塞(blocking)。這是DBA經常會遇到的情況。當出現SQL語句的阻塞時,很多人想查看阻塞的源頭(哪個SQL語句阻塞了哪個SQL),這樣方便直觀、簡潔明瞭的定位問題。但是很多時... ...


    在SQL Server資料庫或OACLE資料庫當中,通常一個會話持有某個資源的鎖,而另一個會話在請求這個資源,就會出現阻塞(blocking)。這是DBA經常會遇到的情況。當出現SQL語句的阻塞時,很多人想查看阻塞的源頭(哪個SQL語句阻塞了哪個SQL),這樣方便直觀、簡潔明瞭的定位問題。但是很多時候,很多場景,我們通過SQL語句並不能或者說不容易定位到阻塞者(Blocker)的SQL語句,當然我們可以很容易找到被阻塞的SQL語句,以及它在等待的鎖資源。下麵我們先分析一下SQL Server資料庫的這類場景,然後分析一下ORACLE資料庫的這類場景。如有不足的地方,敬請指出。

 

在SQL Server當中,我們先準備下麵測試環境(測試用的表和數據)。

 
USE Test;
GO
CREATE TABLE Test 
(
    ID        INT ,
    NAME    VARCHAR(12)
);
 
 
INSERT INTO Test
VALUES (1000, 'Kerry');
 
INSERT INTO Test
VALUES(1001, 'Jimmy');

 

場景1:我們構造這樣一個簡單的場景,例如如下:

 

在會話81中執行下麵SQL語句

BEGIN TRAN
    
    UPDATE Test SET NAME='Tina' WHERE ID=1000;

 

 

在會話72中執行下麵SQL語句

SELECT * FROM TEST;

 

 

在另外一個會話視窗執行下麵語句,查看阻塞(blocker)者和被阻塞者的SQL語句(這裡能夠定位到阻塞者(blocker)的SQL語句)。如下所示

SELECT wt.blocking_session_id                    AS BlockingSessesionId
      ,sp.program_name                           AS Blocking_ProgramName
      ,COALESCE(sp.LOGINAME, sp.nt_username)     AS Blocking_HostName    
      ,ec1.client_net_address                    AS ClientIpAddress
      ,db.name                                   AS DatabaseName        
      ,wt.wait_type                              AS WaitType                    
      ,ec1.connect_time                          AS BlockingStartTime
      ,wt.WAIT_DURATION_MS/1000                  AS WaitDuration
      ,ec1.session_id                            AS BlockedSessionId
      ,h1.TEXT                                   AS BlockedSQLText
      ,h2.TEXT                                   AS BlockingSQLText
FROM sys.dm_tran_locks  AS tl WITH(NOLOCK)
INNER JOIN sys.databases AS db  WITH(NOLOCK)
  ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt  WITH(NOLOCK)
  ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.dm_exec_connections  ec1 WITH(NOLOCK)
  ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections  ec2 WITH(NOLOCK)
  ON ec2.session_id = wt.blocking_session_id
LEFT OUTER JOIN master.dbo.sysprocesses AS sp WITH(NOLOCK)
  ON SP.spid = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1 
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2 

clip_image001

 

但是這個場景是一個非常理想化的場景,實際場景中,可能會話81接下來會去執行其它SQL語句,它並不會一直停留在這個SQL語句上,例如,我們在會話81中執行SELECT GETDATE();這個SQL語句

BEGIN TRAN
    
 UPDATE Test SET NAME='Tina' WHERE ID=1000;
 
 SELECT GETDATE();

clip_image002

 

如上所示,此時查到的Blocker者的SQL語句為"SELECT GETDATE();", 而這個SQL其實和被阻塞的SQL沒有半毛關係。即使使用sp_WhoIsActive這樣專業的SQL亦是如此。

clip_image003

 

當然我們可以查看其等待的鎖對象信息,這也是我們所能追蹤、捕獲的。如下所示:

<Database name="Test">
  <Locks>
    <Lock request_mode="S" request_status="GRANT" request_count="1" />
  </Locks>
  <Objects>
    <Object name="Test" schema_name="dbo">
      <Locks>
        <Lock resource_type="OBJECT" request_mode="IS" request_status="GRANT" request_count="1" />
        <Lock resource_type="PAGE" page_type="*" request_mode="IS" request_status="GRANT" request_count="1" />
        <Lock resource_type="RID" page_type="*" request_mode="S" request_status="WAIT" request_count="1" />
      </Locks>
    </Object>
  </Objects>
</Database>

clip_image004

 

這種場景,如果只是某個會話發出的即席查詢,那麼你幾乎已經很難捕獲到阻塞的源頭UPDATE Test SET NAME='Tina' WHERE ID=1000這個SQL語句了。除非你結合其它一些手段,逆向推斷。

 

場景2:上面查找SQL阻塞的SQL語句,有時候只能定位到某一個存儲過程或一大段即席查詢SQL。

 

例如,下麵一個構造的存儲過程,一個用戶正在一個會話當中執行它,

CREATE PROCEDURE PRC_TEST
AS 
BEGIN 
 
    BEGIN TRAN TR1
 
    UPDATE Test SET NAME='YourName' WHERE ID=1000;
 
    SELECT * FROM sys.sysprocesses WHERE spid=@@SPID;
 
    WAITFOR DELAY '00:00:20';
 
    COMMIT TRAN TR1;
 
END
GO 

 

另外一個用戶在另外一個會話執行下麵查詢SQL語句

 
SELECT * FROM TEST;

 

查看阻塞的歷史記錄

clip_image005

 

你會看到捕獲的是整個存儲過程,當然這個測試案例很容易知道是那個SQL語句阻塞了,實際的存儲過程可能業務很複雜,SQL語句也非常多,你想從一個存儲過程裡面找到阻塞者(Blocker)的SQL語句其實是非常麻煩的。需要你仔細甄別,當存儲過程的業務邏輯複雜,SQL語句非常多時,這是一個頭痛的事情

其實遇到這些場景,我們大可不必一定要查看阻塞這(Blocker)的具體SQL,我們只需要查看被阻塞者,等待的鎖對象資源的相關信息即可,你可以大致判斷到底是一個什麼類型的SQL導致了這類阻塞。

 

 

那麼我們接下來看看ORACLE資料庫場景吧。我們先準備一個測試環境(測試表和相關數據)

 

CREATE TABLE "TEST"."TEST" 
(    "ID" NUMBER, 
    "NAME" VARCHAR2(12)
);
 
INSERT INTO TEST
SELECT 1001, 'jimmy' FROM DUAL UNION ALL
SELECT 1002, 'Kerry' FROM DUAL;
 
COMMIT;

 

 

接下來我們在會話視窗一執行下麵SQL:

[oracle@DB-Server ~]$ sqlplus test/test
 
SQL*Plus: Release 11.2.0.1.0 Production on Tue Aug 30 10:16:43 2016
 
Copyright (c) 1982, 2009, Oracle.  All rights reserved.
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Apache Spark是一個圍繞速度、易用性和複雜分析構建的大數據處理框架,最初在2009年由加州大學伯克利分校的AMPLab開發,並於2010年成為Apache的開源項目之一,與Hadoop和Storm等其他大數據和MapReduce技術相比,Spark有如下優勢: Spark提供了一個全面、統 ...
  • ...
  • 最近接觸了很多資料庫的東西,本來是一直接觸的是sql server,不過由於項目需要就開始對mysql進行了連接。下麵就讓我這個菜鳥淺談下經驗吧。 對於C++連接mysql,我不太喜歡多下載一個軟體mysqlodbc,所以採用的是通過mysql自己的API函數進行連接: 1、使用API的方式連接,需 ...
  • 先介紹一下環境: 我是異機恢復,和本機操作一樣。 一、 全量備份 步驟: ./innobackupex --user=root --password=root --host=172.17.210.112 --parallel=4 --throttle=400 --stream=tar /mysqlb ...
  • 由於工作需要,開始使用mysql資料庫,已經好久沒有使用了。基本已經忘了差不多。今天重新安裝配置了一下,寫個隨筆記錄一下,以免自己以後需要的時候翻看,如有不正確或需要補充的,希望大家多多留言。 首先下載mysql,我直接通過百度軟體中下載的“mysql-5.6.24-win32.1432006610 ...
  • 介紹 從archive單詞的解釋我們大概可以明白這個存儲引擎的用途,這個存儲引擎基本上用於數據歸檔;它的壓縮比非常的高,存儲空間大概是innodb的10-15分之一所以它用來存儲歷史數據非常的適合,由於它不支持索引同時也不能緩存索引和數據,所以它不適合作為併發訪問表的存儲引擎。Archivec存儲引 ...
  • MySql Server安裝步驟 1安裝MySql Server 2 安裝MySqlServer管理工具 解壓中文語言包,將文件複製到安裝目錄下覆蓋 文件覆蓋後,打開軟體設置語言為中文(CN) 3 MySqlServer開發註意事項(C#) public class Cmd { /// <summa ...
  • 總結了27條機器學習相關的Awesome系列,如有遺漏敬請指出。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...