為什麼資料庫有時候不能定位阻塞(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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...