古之成大事者,不唯有超世之才,亦唯有堅韌不拔之志也!

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            3 隨筆 :: 44 文章 :: 1 評論 :: 0 Trackbacks

          雖然不能完全避免死鎖,但可以使死鎖的數量減至最少。將死鎖減至最少可以增加事務的吞吐量并減少系統開銷,因為只有很少的事務:

          • 回滾,而回滾會取消事務執行的所有工作。
          • 由于死鎖時回滾而由應用程序重新提交。

          下列方法有助于最大限度地降低死鎖:

          • 按同一順序訪問對象。
          • 避免事務中的用戶交互。
          • 保持事務簡短并在一個批處理中。
          • 使用低隔離級別。
          • 使用綁定連接。

          按同一順序訪問對象

          如果所有并發事務按同一順序訪問對象,則發生死鎖的可能性會降低。例如,如果兩個并發事務獲得 Supplier表上的鎖,然后獲得 Part表上的鎖,則在其中一個事務完成之前,另一個事務被阻塞在 Supplier表上。第一個事務提交或回滾后,第二個事務繼續進行。不發生死鎖。將存儲過程用于所有的數據修改可以標準化訪問對象的順序。

          避免事務中的用戶交互

          避 免編寫包含用戶交互的事務,因為運行沒有用戶交互的批處理的速度要遠遠快于用戶手動響應查詢的速度,例如答復應用程序請求參數的提示。例如,如果事務正在 等待用戶輸入,而用戶去吃午餐了或者甚至回家過周末了,則用戶將此事務掛起使之不能完成。這樣將降低系統的吞吐量,因為事務持有的任何鎖只有在事務提交或 回滾時才會釋放。即使不出現死鎖的情況,訪問同一資源的其它事務也會被阻塞,等待該事務完成。

          保持事務簡短并在一個批處理中


          在同一數據庫中并發執行多個需要長時間運行的事務時通常發生死鎖。事務運行時間越長,其持有排它鎖或更新鎖的時間也就越長,從而堵塞了其它活動并可能導致死鎖。

          保持事務在一個批處理中,可以最小化事務的網絡通信往返量,減少完成事務可能的延遲并釋放鎖。

          使用低隔離級別

          確定事務是否能在更低的隔離級別上運行。執行提交讀允許事務讀取另一個事務已讀取(未修改)的數據,而不必等待第一個事務完成。使用較低的隔離級別(例如提交讀)而不使用較高的隔離級別(例如可串行讀)可以縮短持有共享鎖的時間,從而降低了鎖定爭奪。


          使用綁定連接


          使用綁定連接使同一應用程序所打開的兩個或多個連接可以相互合作。次級連接所獲得的任何鎖可以象由主連接獲得的鎖那樣持有,反之亦然,因此不會相互阻塞


          檢測死鎖


          如果發生死鎖了,我們怎么去檢測具體發生死鎖的是哪條SQL語句或存儲過程?


          這時我們可以使用以下存儲過程來檢測,就可以查出引起死鎖的進程和SQL語句。SQL Server自帶的系統存儲過程sp_who和sp_lock也可以用來查找阻塞和死鎖, 但沒有這里介紹的方法好用。



          use master
          go
          createprocedure sp_who_lock
          as
          begin
          declare@spidint,@blint,
          @intTransactionCountOnEntryint,
          @intRowcountint,
          @intCountPropertiesint,
          @intCounterint

          createtable #tmp_lock_who (
          id
          intidentity(1,1),
          spid
          smallint,
          bl
          smallint)

          IF@@ERROR<>0RETURN@@ERROR

          insertinto #tmp_lock_who(spid,bl) select0 ,blocked
          from (select*from sysprocesses where blocked>0 ) a
          wherenotexists(select*from (select*from sysprocesses where blocked>0 ) b
          where a.blocked=spid)
          unionselect spid,blocked from sysprocesses where blocked>0

          IF@@ERROR<>0RETURN@@ERROR

          -- 找到臨時表的記錄數
          select@intCountProperties=Count(*),@intCounter=1
          from #tmp_lock_who

          IF@@ERROR<>0RETURN@@ERROR

          if@intCountProperties=0
          select'現在沒有阻塞和死鎖信息'as message

          -- 循環開始
          while@intCounter<=@intCountProperties
          begin
          -- 取第一條記錄
          select@spid= spid,@bl= bl
          from #tmp_lock_who where Id =@intCounter
          begin
          if@spid=0
          select'引起數據庫死鎖的是: '+CAST(@blASVARCHAR(10)) +'進程號,其執行的SQL語法如下'
          else
          select'進程號SPID:'+CAST(@spidASVARCHAR(10))+''+'進程號SPID:'+CAST(@blASVARCHAR(10)) +'阻塞,其當前進程執行的SQL語法如下'
          DBCC INPUTBUFFER (@bl )
          end

          -- 循環指針下移
          set@intCounter=@intCounter+1
          end

          droptable #tmp_lock_who

          return0
          end


          殺死鎖和進程


          如何去手動的殺死進程和鎖?最簡單的辦法,重新啟動服務。但是這里要介紹一個存儲過程,通過顯式的調用,可以殺死進程和鎖。



          use master
          go

          ifexists (select*from dbo.sysobjects where id =object_id(N'[dbo].[p_killspid]') andOBJECTPROPERTY(id, N'IsProcedure') =1)
          dropprocedure[dbo].[p_killspid]
          GO

          createproc p_killspid
          @dbnamevarchar(200) --要關閉進程的數據庫名
          as
          declare@sqlnvarchar(500)
          declare@spidnvarchar(20)

          declare #tb cursorfor
          select spid=cast(spid asvarchar(20)) from master..sysprocesses where dbid=db_id(@dbname)
          open #tb
          fetchnextfrom #tb into@spid
          while@@fetch_status=0
          begin
          exec('kill '+@spid)
          fetchnextfrom #tb into@spid
          end
          close #tb
          deallocate #tb
          go

          --用法
          exec p_killspid 'newdbpy'

          posted on 2008-05-16 10:36 goto 閱讀(467) 評論(0)  編輯  收藏 所屬分類: 數據庫
          主站蜘蛛池模板: 寿光市| 沅江市| 土默特左旗| 什邡市| 嘉祥县| 通渭县| 万载县| 华安县| 慈利县| 岳阳市| 容城县| 麻江县| 五家渠市| 通道| 吉木萨尔县| 巴楚县| 平凉市| 洛川县| 珠海市| 华安县| 宜君县| 德州市| 扎兰屯市| 乐东| 宁化县| 潞城市| 东莞市| 武乡县| 衡山县| 新竹县| 浦县| 永靖县| 镶黄旗| 罗江县| 静宁县| 保德县| 高碑店市| 玉山县| 闽侯县| 泰安市| 临清市|