1. 程式人生 > >mssql 檢視語句執行時間異常的原因(SQLServer)

mssql 檢視語句執行時間異常的原因(SQLServer)

經常有開發同事反映如下情況:我有一條語句或者一個JOB昨天跑半個小時就完成了,今天怎麼跑了兩個小時還沒有完成?

是不是資料庫出現問題了?

    資料庫語句執行時間異常,其實是一個比較複雜的情況,因為資料是不斷變動的,今天好好的一條語句,有可能明天執行就

不在預計的時間內了,這個場景是沒辦法完全重溯的,即便有當時的備份資料,但是當時的伺服器壓力是沒有辦法知道和營造

的;但是好在現在不是要調查昨天語句跑時間異常的原因,而是要找到現在語句執行異常的原因,現在的情況還正在進行著呢,

所以我們可以根據語句目前的情況,初步來排查一下;

    其實要考慮的問題比較多:

    1. 索引是否正常(索引是否損壞、有沒有人刪除索引等);

    2. 統計資訊是否過時;

    3. 語句執行計劃是否發生偏移(和索引、統計資訊以及資料量都有關係);

    4. 語句是否有bug;

    5. 是否發生的阻塞;

    6. 系統資源是否遇到瓶頸;

    .........

    這麼多的情況都考慮的話我們很難下手,一般解決這個問題我們都需要採用比較快的方式來做排查,以下方法主要針對5和6兩

個方面進行,因為這兩個方面是最常見的情況。

我們來簡單模擬一下排查過程:

1. 建立測試表和資料

複製程式碼
USE [master]
GO

/****** Object:  Table [dbo].[a]    Script Date: 01/17/2012 16:46:34 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[a]( [id] [int] IDENTITY(1,1) NOT NULL, [name] [varchar](100) NULL ) ON [PRIMARY] GO SET ANSI_PADDING OFF GO insert into a values('aa'),('bb'),('cc')
複製程式碼

2. 製造阻塞:開兩個session,分別執行下面的語句

複製程式碼
--Session 1use master
go
begin tran
update A set name='abc'
where id=2 --rollback
--Session 2select * from a 
複製程式碼

因為Session1 的Update語句沒有能夠提交,所以此時Session2 過程會被阻塞


3. 分析排查:

  我們首先需要查詢下此時資料庫中是否存在阻塞:

--Blockedselect * from sys.sysprocesses with(nolock) where blocked<>0


 我們看到了阻塞的記錄,53阻塞了56,被阻塞的資源是:dbid 1 file 1 page 307;

 接下來我們需要知道阻塞和被阻塞的是什麼語句,有兩種方式:

 a. dbcc inputbuffer

 b. sys.dm_exec_sql_text

 方法一與方法二相比:

   優點:方法一能顯示非活動session的語句,方法二隻能查活動的session(通過sp_who2 active 能顯示是否活動);

   缺點:方法一隻能一個一個查詢,方法二可以多個一起查詢;

方法一:

--No1:dbcc inputbuffer(53)
go
dbcc inputbuffer(56)

方法二:

複製程式碼
--No2:SELECT
    S.session_id, R.blocking_session_id,
    S.host_name, S.login_name, 
    databaseName=DB_NAME(R.database_id),R.command, R.status,
    current_execute_sql = SUBSTRING(T.text,
                R.statement_start_offset / 2 + 1,
                CASE
                    WHEN statement_end_offset = -1 THEN LEN(T.text)
                    ELSE (R.statement_end_offset - statement_start_offset) / 2+1
                END),
    S.program_name,
    S.status,
    S.cpu_time, memory_usage_kb = S.memory_usage * 8, S.reads, S.writes,
    S.transaction_isolation_level,
    C.connect_time, C.last_read, C.last_write,
    C.net_transport, C.client_net_address, C.client_tcp_port, C.local_tcp_port,
    R.start_time, 
    R.wait_time, R.wait_type, R.last_wait_type, R.wait_resource,
    R.open_transaction_count, R.transaction_id
    
FROM sys.dm_exec_sessions S
    LEFT JOIN sys.dm_exec_connections C
        ON S.session_id = C.session_id
    LEFT JOIN sys.dm_exec_requests R
        ON S.session_id = R.session_id
            AND C.connection_id = R.connection_id
    OUTER APPLY sys.dm_exec_sql_text(R.sql_handle) T
WHERE  S.is_user_process = 1  -- 如果不限制此條件,則查詢所有程序(系統和使用者程序)and s.session_id in(53,56)
複製程式碼

我們看到方法一兩條語句都能查出來,而方法二隻能查出一個語句;

到這裡,我們已經能判斷語句執行慢的原因是被阻塞了,我們再來查查阻塞的原因是什麼,可以通過以下語句檢視:

select request_session_id,resource_type,db_name(resource_database_id) as DBName,resource_description,
request_mode,request_type,request_status from sys.dm_tran_locks where request_session_id in(56,53)
order by request_session_id

可以看到,56處於WAIT狀態,它在等待獲取1:307:1 上的一個共享鎖,但是1:307:1上被53的一個排他鎖佔據了(GRANT代表

已獲得資源,正在執行),因此56必須等待53上的排他鎖釋放後才能繼續執行;於是我們轉而調查53排他鎖沒有釋放的原因;可能是

53需要的其他資源被其他程序佔有了,在等待其他程序釋放鎖;也可能是因為Update語句更新的資料量過多,需要的時間比較長,不

能夠及時的釋放鎖;還有就是我們現在的情況,沒有提交事物了(語句中可以直接看到);阻塞的排查方法都是類似的。

如果語句並沒有被其他語句blocked呢? 那我們需要再進一步查詢的原因就是Wait了,前面已經有wait的相關查詢,下面我們來查下

更具體的資訊:

複製程式碼
-- wait & lockselect lo.request_session_id as [Session],
DB_NAME(lo.resource_database_id) as Dbname,
lo.resource_type as [Type],
lo.resource_description,
lo.request_mode,
lo.request_owner_type,
lo.request_status,
case when lo.resource_type='OBJECT' then OBJECT_NAME(lo.resource_associated_entity_id)
     when lo.resource_associated_entity_id IS NULL OR lo.resource_associated_entity_id=0
     then NULL
     else OBJECT_NAME(p.object_id) 
     end as Associated_Entity,
wt.blocking_session_id,wt.resource_description
from 
sys.dm_tran_locks lo with(nolock)
left join sys.partitions p with(nolock)
on lo.resource_associated_entity_id=p.partition_id
left join sys.dm_os_waiting_tasks wt with(nolock)
on lo.lock_owner_address=wt.resource_address
where lo.request_session_id>50
and lo.request_session_id=56 
order by [Session] ,[TYPE]
複製程式碼

上面可以看到,56在獲取共享資源1:307:1時,遇到了等待,當然這裡的等待還是被53阻塞了,但是等待會有多種原因的等待,我們查

一下當前的等待資訊:

複製程式碼
--current wait infoselect wait_type,COUNT(0) as num_waiting_tasks,
SUM(wait_duration_ms) as total_wait_time_ms
 from sys.dm_os_waiting_tasks with(nolock)
where session_id>50
group by wait_type
order by wait_type
複製程式碼

這裡可以看到是鎖等待(Wait_Type),還有很多資源型別的等待,值的重點關注的有:
  Memory:CMEMTHREAD ,RESOURCE_SEMAPHORE
     CMEMTHREAD:
       說明和原因:計劃快取出現問題的標誌(大量計劃加入或者移出);
       解決:     使用引數化的查詢或者設定資料庫強制引數化(forced parameterization)

     RESOURCE_SEMAPHORE:
       說明和原因:記憶體密集型查詢無法獲得請求的記憶體;其他程序消耗了太多的記憶體;
       解決:     為資料庫新增合適的索引或者增加記憶體

  IO:IO_COMPLETION,ASYNC_IO_COMPLETION,WRITELOG,PAGEIOLATCH_*

  CPU: CXPACKET,SOS_SCHEDULER_YIELD
       CXPACKET:
          說明和原因:並行處理等待型別,並行同步等待;
          解決:     可以通過修改並行度的值(或者禁用)解決;
       SOS_SCHEDULER_YIELD:
          說明和原因:任務執行到時間片尾,讓出排程器給其他任務執行;
          解決:     需要處理能力更好的CPU
 
  Network:ASYNC_NETWORK_IO,DBMIRROR_SEND
       ASYNC_NETWORK_IO: 網絡卡頻寬飽和或者客戶端不能及時把結果取走;
       DBMIRROR_SEND:  網路頻寬不足以支援映象事務量或者映象資料庫超出限額;

  鎖阻塞:LCK_*    


我們可以統計下,我們資料庫最多的20種等待型別:

複製程式碼
--total wait infoselect top 20 wait_type,SUM(waiting_tasks_count) waiting_tasks_count,
SUM(wait_time_ms)as total_wait_time_ms,
SUM(signal_wait_time_ms) as total_signal_wait_time_ms
from sys.dm_os_wait_stats with(nolock)
where wait_type not in
 --system wait type('LAZYWRITER_SLEEP','REQUEST_FOR_DEADLOCK_SEARCH','SQLTRACE_BUFFER_FLUSH',
 'XE_TIMER_EVENT','FT_IFTS_SCHEDULER_IDLE_WAIT','LOGMGR_QUEUE','CHECKPOINT_QUEUE',
 'SLEEP_TASK','BROKER_IO_FLUSH','BROKER_TASK_STOP','BROKER_TO_FLUSH','BROKER_EVENTHANDLER')
group by wait_type
order by total_wait_time_ms desc
複製程式碼

通過這個我們可以從中看出DB等待主要集中在哪些方面,如果是在CPU、IO、Memory、Lock等上面等待時間很長,說明我們

的資料庫需要做某些方面的優化了。

相關推薦

mssql 檢視語句執行時間異常原因SQLServer

經常有開發同事反映如下情況:我有一條語句或者一個JOB昨天跑半個小時就完成了,今天怎麼跑了兩個小時還沒有完成? 是不是資料庫出現問題了?     資料庫語句執行時間異常,其實是一個比較複雜的情況,因為資料是不斷變動的,今天好好的一條語句,有可能明天執行就 不在預計的時間內了

MySQL 檢視語句執行時間 詳解

方法1> 使用 show profiles 進行檢視# 檢視 profile 是不是開啟的,預設是不開啟mysql> show variables like "%pro%";+-------

Hue上檢視spark執行報錯資訊

點選Hue報錯頁面,找到application_ID 根據application_ID到yarn介面(http://bigdata.lhx.com:8088/cluster)找到完整資訊 點選ID或者history進入logs介面 詳細報錯資訊:spark找不到叢集中asmp資料

執行異常處理通用

1 public class ChildThread implements Runnable { 2 private static ChildThreadExceptionHandler exceptionHandler; 3 4 static { 5 except

檢視sql語句執行時間/測試sql語句效能

一,通過設定STATISTICS我們可以檢視執行SQL時的系統情況。選項有PROFILE,IO ,TIME。介紹如下: SET STATISTICS PROFILE ON:顯示分析、編譯和執行查詢所需的時間(以毫秒為單位)。  SET STATISTICS IO ON:

mysql 如何檢視sql語句執行時間和效率

檢視執行時間 1 show profiles; 2 show variables;檢視profiling 是否是on狀態; 3 如果是off,則 set profiling = 1; 4 執行自己的sql語句; 5 show profiles;就可以查

使用keil的除錯模式檢視程式碼執行時間以51微控制器程式碼為例

1,在 Project>Options for Target[你的專案名稱] 裡設定晶振頻率為實際微控制器晶振頻率 下圖中紅圈內即為晶振頻率單位為MHZ 2,選擇選單 Debug>Start/Stop Debug Session

mysql 如何查看sql語句執行時間和效率

訪問 執行時間 subquery ber 如果 pan from xtra 重要 查看執行時間 1 show profiles; 2 show variables;查看profiling 是否是on狀態; 3 如果是off,則 set profiling = 1; 4 執

使用eclipse執行maven-release-plugin插件發布jar異常問題.project(Cannot prepare the release because you have local modifications )

ins eclips ica svn excludes one list ati .project 開發是用的eclipse,裏面有工程文件.project這種文件,運行release:prepare的時候報異常: Cannot prepare the release be

oracle中for update語句執行時間過長的問題

oracle執行查詢語句SELECT s.sid, s.serial# FROM v$locked_object lo, dba_objects ao, v$session s WHERE ao.object_id = lo.object_id AND lo.session_id = s.sid 查出的兩個字

Ajax不執行回調函數的原因

返回 ajax 數據 回調 今天 key 但是 json 數據格式 今天用ajax的post請求後臺,但是始終不執行回調函數,經查得知,ajax不執行回調函數的原因如下: jquery中規定返回的JSON字符串的KEY要用引號括起來,如{“result”: 1}這樣才可以。

Java面向物件與多執行緒綜合實驗異常處理

理解異常的基本概念;瞭解Java異常的層次結構;熟悉並掌握Java異常的捕獲處理方法。 (1)閱讀Java™ Platform, Standard Edition 8 API Specification文件,瞭解後續程式設計中將要處理的IOException及其子類FileNotFoundE

SQL Server調優系列進階篇查詢語句執行幾個指標值監測

前言 上一篇我們分析了查詢優化器的工作方式,其中包括:查詢優化器的詳細執行步驟、篩選條件分析、索引項優化等資訊。 本篇我們分析在我們執行的過程中幾個關鍵指標值的檢測。 通過這些指標值來分析語句的執行問題,並且分析其優化方式。 通過本篇我們可以學習到調優中經常利用的幾個利器! 廢話少說,開始本篇的正題

Python語句執行時間測試

可以使用timeit模組中的Timer物件來實現。 Timer接收兩個引數,第一個引數是“多次執行的語句”,第二個引數是“只在開始執行一次的語句” e.g.我們為了測試list的append方法和s

C# SQL語句執行時間過長在操作完成之前超時時間已過或伺服器未響應問題的解決

   SqlCommand sold_cmd = new SqlCommand(sql_sold,conn);   sold_cmd.CommandTimeout = 300;   SqlCommand detail_c

查詢Oracle資料庫的物化檢視執行時間

其中由於之前對total_time的一個錯誤理解導致這個SQL查出來的時間存在問題。 total_time:表示此物化檢視從建立開始到此次查詢,這個時間段中此物化檢視的總共的執行時間。而不是此物化檢視

python:檢視程式執行時間

需求 檢視程式執行時間; 比較不同演算法的執行效率 方法 time模組中的clock() 例項 import time def test(): start=time.cl

Windows小知識關聯檔案開啟型別,快捷鍵,命令列語句執行原理,快速編輯模式

如何關聯檔案的開啟型別 開啟命令執行工具,注意,win7,win8及以上的環境,要用管理員方式執行執行assoc.java=nppfile執行ftype nppfile="C:\ProgramFile

在pycharm中編輯Python程式 迴圈、IF語句報錯的原因格式問題

      在pycharm中編輯程式時候,往往程式碼正確,但不知道哪裡報錯,這裡以下面一個例子來說明程式碼格式的規範性在pycharm中的重要性。       題目:編寫函式,接受一個正偶數為引數,輸出2個素數,且這2個素數之和等於原正偶數,存在多組符合的素數,則全部輸出

C#檢視程式碼執行時間

//引用名稱空間 using System.Diagnostics; Stopwatch swatch = new Stopwatch(); //建立Stopwatch 例項 swatch.Start(); //開始計時 code.... /