减少SQL Server数据库死锁的方法

 
减少SQL Server数据库死锁的方法


如果两个用户进程分别锁定了不同的资源,接着又试图锁定对方所锁定的资源,就会产生死锁。此时,SQL Server将自动地选择并中止其中一个进程以解除死锁,使得另外一个进程能够继续处理。系统将回退被中止的事务,并向被回退事务的用户发送错误信息。
  
  大多数设计良好的应用都会在接收到这个错误信息之后重新提交该事务,此时提交成功的可能性是很大的。但是,如果服务器上经常出现这种情况,就会显著地降低服务器性能。为避免死锁,设计应用应当遵循一定的原则,包括:
  
  
  
  ▲ 让应用每次都以相同的次序访问服务器资源。
  
  ▲ 在事务期间禁止任何用户输入。应当在事务开始之前收集用户输入。
  
  ▲ 尽量保持事务的短小和简单。
  
  ▲ 如合适的话,为运行事务的用户连接指定尽可能低的隔离级别。[适用于6.5,7.0,2000]
  
  
  
  此外,对于SQL Server的死锁问题,下面是几则实践中很有用的小技巧。
  
  
  ■ 使用SQL Server Profiler的Create Trace Wizard运行”Identify The Cause of a Deadlock”跟踪来辅助识别死锁问题,它将提供帮助查找数据库产生死锁原因的原始数据。[适用于7.0,2000]
  
  ■ 如果无法消除应用中的所有死锁,请确保提供了这样一种程序逻辑:它能够在死锁出现并中止用户事务之后,以随机的时间间隔自动重新提交事务。这里等待时间的随机性非常重要,这是因为另一个竞争的事务也可能在等待,我们不应该让两个竞争的事务等待同样的时间,然后再在同一时间执行它们,这样的话将导致新的死锁。[适用于6.5,7.0,2000]
  
  ■ 尽可能地简化所有T-SQL事务。此举将减少各种类型的锁的数量,有助于提高SQL Server应用的整体性能。如果可能的话,应将较复杂的事务分割成多个较简单的事务。[适用于6.5,7.0,2000]
  
  ■ 所有条件逻辑、变量赋值以及其他相关的预备设置操作应当在事务之外完成,而不应该放到事务之内。永远不要为了接受用户输入而暂停某个事务,用户输入应当总是在事务之外完成。[适用于6.5,7.0,2000]
  
  ■ 在存储过程内封装所有事务,包括BEGIN TRANSACTION和COMMIT TRANSACTION语句。此举从两个方面帮助减少阻塞的锁。首先,它限制了事务运行时客户程序和SQL Server之间的通信,从而使得两者之间的任何消息只能出现于非事务运行时间(减少了事务运行的时间)。其次,由于存储过程强制它所启动的事务或者完成、或者中止,从而防止了用户留下未完成的事务(留下未撤销的锁)。[适用于6.5,7.0,2000]
  
  ■ 如果客户程序需要先用一定的时间检查数据,然后可能更新数据,也可能不更新数据,那么最好不要在整个记录检查期间都锁定记录。假设大部分时间都是检查数据而不是更新数据,那么处理这种特殊情况的一种方法就是:先选择出记录(不加UPDATE子句。UPDATE子句将在记录上加上共享锁),然后把它发送给客户。
  
  如果用户只查看记录但从来不更新它,程序可以什么也不做;反过来,如果用户决定更新某个记录,那么他可以通过一个WHERE子句检查当前的数据是否和以前提取的数据相同,然后执行UPDATE。
  
  类似地,我们还可以检查记录中的时间标识列(如果它存在的话)。如果数据相同,则执行UPDATE操作;如果记录已经改变,则应用应该提示用户以便用户决定如何处理。虽然这种方法需要编写更多的代码,但它能够减少加锁时间和次数,提高应用的整体性能。[适用于6.5,7.0,2000]
  
  ■ 尽可能地为用户连接指定具有最少限制的事务隔离级别,而不是总是使用默认的READ COMMITTED。为了避免由此产生任何其他问题,应当参考不同隔离级别将产生的效果,仔细地分析事务的特性。[适用于6.5,7.0,2000]
  
  ■ 使用游标会降低并发性。为避免这一点,如果可以使用只读的游标则应该使用READ_ONLY游标选项,否则如果需要进行更新,尝试使用OPTIMISTIC游标选项以减少加锁。设法避免使用SCROLL_LOCKS游标选项,该选项会增加由于记录锁定引起的问题。[适用于6.5,7.0,2000]
  
  ■ 如果用户抱怨说他们不得不等待系统完成事务,则应当检查服务器上的资源锁定是否是导致该问题的原因。进行此类检查时可以使用SQL Server Locks Object: Average Wait Time (ms),用该计数器来度量各种锁的平均等待时间。
  
  如果可以确定一种或几种类型的锁导致了事务延迟,就可以进一步探究是否可以确定具体是哪个事务产生了这种锁。Profiler是进行这类具体分析的最好工具。[适用于7.0,2000]
  
  ■ 使用sp_who和sp_who2(SQL Server Books Online没有关于sp_who2的说明,但sp_who2提供了比sp_who更详细的信息)来确定可能是哪些用户阻塞了其他用户。[适用于6.5,7.0,2000]
  
  ■ 试试下面的一个或多个有助于避免阻塞锁的建议:1)对于频繁使用的表使用集簇化的索引;2)设法避免一次性影响大量记录的T-SQL语句,特别是INSERT和UPDATE语句;3)设法让UPDATE和DELETE语句使用索引;4)使用嵌套事务时,避免提交和回退冲突。[适用于6.5,7.0,2000]
 
 

sql 死锁

其实所有的死锁最深层的原因就是一个:资源竞争 表现一:
    一个用户A 访问表A(锁住了表A),然后又访问表B
    另一个用户B 访问表B(锁住了表B),然后企图访问表A
 
    这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B,才能继续,好了他老人家就只好老老实实在这等了
    同样用户B要等用户A释放表A才能继续这就死锁了
解决方法:
    这种死锁是由于你的程序的BUG产生的,除了调整你的程序的逻辑别无他法
    仔细分析你程序的逻辑,
    1:尽量避免同时锁定两个资源
    2: 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源.
  
表现二:
    用户A读一条纪录,然后修改该条纪录
    这是用户B修改该条纪录
    这里用户A的事务里锁的性质由共享锁企图上升到独占锁(for update),而用户B里的独占锁由于A有共享锁存在所以必须等A释
放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。
    这种死锁比较隐蔽,但其实在稍大点的项目中经常发生。
解决方法:
    让用户A的事务(即先读后写类型的操作),在select 时就是用Update lock
    语法如下:
    select * from table1 with(updlock) where ….
==========================
 
在联机事务处理(OLTP)的数据库应用系统中,多用户、多任务的并发性是系统最重要的技术指标之一。为了提高并发性,目前大部分RDBMS都采用加锁技术。然而由于现实环境的复杂性,使用加锁技术又不可避免地产生了死锁问题。因此如何合理有效地使用加锁技术,最小化死锁是开发联机事务处理系统的关键。    
  死锁产生的原因    
  在联机事务处理系统中,造成死机主要有两方面原因。一方面,由于多用户、多任务的并发性和事务的完整性要求,当多个事务处理对多个资源同时访问时,若双方已锁定一部分资源但也都需要对方已锁定的资源时,无法在有限的时间内完全获得所需的资源,就会处于无限的等待状态,从而造成其对资源需求的死锁。    
  另一方面,数据库本身加锁机制的实现方法不同,各数据库系统也会产生其特殊的死锁情况。如在Sybase   SQL   Server   11中,最小锁为2K一页的加锁方法,而非行级锁。如果某张表的记录数少且记录的长度较短(即记录密度高,如应用系统中的系统配置表或系统参数表就属于此类表),被访问的频率高,就容易在该页上产生死锁。    
  几种死锁情况及解决方法    
  清算应用系统中,容易发生死锁的几种情况如下:      
  ●   不同的存储过程、触发器、动态SQL语句段按照不同的顺序同时访问多张表;      
  ●   在交换期间添加记录频繁的表,但在该表上使用了非群集索引(non-clustered);      
  ●   表中的记录少,且单条记录较短,被访问的频率较高;    
  ●   整张表被访问的频率高(如代码对照表的查询等)。    
  以上死锁情况的对应处理方法如下:    
  ●   在系统实现时应规定所有存储过程、触发器、动态SQL语句段中,对多张表的操作总是使用同一顺序。如:有两个存储过程proc1、proc2,都需要访问三张表zltab、z2tab和z3tab,如果proc1按照zltab、z2tab和z3tab的顺序进行访问,那么,proc2也应该按照以上顺序访问这三张表。    
  ●   对在交换期间添加记录频繁的表,使用群集索引(clustered),以减少多个用户添加记录到该表的最后一页上,在表尾产生热点,造成死锁。这类表多为往来账的流水表,其特点是在交换期间需要在表尾追加大量的记录,并且对已添加的记录不做或较少做删除操作。    
  ●   对单张表中记录数不太多,且在交换期间select或updata较频繁的表可使用设置每页最大行的办法,减少数据在表中存放的密度,模拟行级锁,减少在该表上死锁情况的发生。这类表多为信息繁杂且记录条数少的表。    
  如:系统配置表或系统参数表。在定义该表时添加如下语句:    
  with   max_rows_per_page=1    
  ●   在存储过程、触发器、动态SQL语句段中,若对某些整张表select操作较频繁,则可能在该表上与其他访问该表的用户产生死锁。对于检查账号是否存在,但被检查的字段在检查期间不会被更新等非关键语句,可以采用在select命令中使用at   isolation   read   uncommitted子句的方法解决。该方法实际上降低了select语句对整张表的锁级别,提高了其他用户对该表操作的并发性。在系统高负荷运行时,该方法的效果尤为显著。    
  例如:    
  select*from   titles   at   isolation   read   uncommitted    
  ●   对流水号一类的顺序数生成器字段,可以先执行updata流水号字段+1,然后再执行select获取流水号的方法进行操作。    
  小结    
  笔者对同城清算系统进行压力测试时,分别对采用上述优化方法和不采用优化方法的两套系统进行测试。在其他条件相同的情况下,相同业务笔数、相同时间内,死锁发生的情况如下:    
  采用优化方法的系统:   0次/万笔业务;      
  不采用优化方法的系统:50~200次/万笔业务。    
  所以,使用上述优化方法后,特别是在系统高负荷运行时效果尤为显著。总之,在设计、开发数据库应用系统,尤其是OLTP系统时,应该根据应用系统的具体情况,依据上述原则对系统分别优化,为开发一套高效、可靠的应用系统打下良好的基础。    
 
============
–转  
  if   exists   (select   *   from   dbo.sysobjects   where   id   =   object_id(N'[dbo].[sp_who_lock]’)   and   OBJECTPROPERTY(id,   N’IsProcedure’)   =   1)  
  drop   procedure   [dbo].[sp_who_lock]  
  GO  
  /***************************************************************************  
  //     创建   :   fengyu     邮件   :   maggiefengyu@tom.com     日期   :2004-04-30  
  //     修改   :   从http://www.csdn.net/develop/Read_Article.asp?id=26566学习到并改写      
  //     说明   :   查看数据库里阻塞和死锁情况  
  ***************************************************************************/  
  use   master  
  go  
  create   procedure   sp_who_lock  
  as  
  begin  
  declare   @spid   int,@bl   int,  
  @intTransactionCountOnEntry   int,  
                  @intRowcount   int,  
                  @intCountProperties   int,  
                  @intCounter   int  
   
  create   table   #tmp_lock_who   (  
  id   int   identity(1,1),  
  spid   smallint,  
  bl   smallint)  
   
  IF   @@ERROR<>0   RETURN   @@ERROR  
   
  insert   into   #tmp_lock_who(spid,bl)   select     0   ,blocked  
      from   (select   *   from   sysprocesses   where     blocked>0   )   a    
      where   not   exists(select   *   from   (select   *   from   sysprocesses   where     blocked>0   )   b    
      where   a.blocked=spid)  
      union   select   spid,blocked   from   sysprocesses   where     blocked>0  
   
  IF   @@ERROR<>0   RETURN   @@ERROR  
     
  —   找到临时表的记录数  
  select   @intCountProperties   =   Count(*),@intCounter   =   1  
  from   #tmp_lock_who  
   
  IF   @@ERROR<>0   RETURN   @@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(@bl   AS   VARCHAR(10))   +   ‘进程号,其执行的SQL语法如下’  
    else  
                          select   ‘进程号SPID:’+   CAST(@spid   AS   VARCHAR(10))+   ‘被’   +   ‘进程号SPID:’+   CAST(@bl   AS   VARCHAR(10))   +’阻塞,其当前进程执行的SQL语法如下’  
    DBCC   INPUTBUFFER   (@bl   )  
  end  
   
  —   循环指针下移  
  set   @intCounter   =   @intCounter   +   1  
  end  
   
   
  drop   table   #tmp_lock_who  
   
  return   0  
  end   
 
==========================
呵呵,解决死锁,光查出来没有多大用处,我原来也是用这个存储过程来清理死锁的  
  我解决死锁的方式主要用了:  
  1   优化索引  
  2   对所有的报表,非事务性的select   语句   在from   后都加了   with   (nolock)   语句  
  3   对所有的事务性更新尽量使用相同的更新顺序来执行  
  现在已解决了死锁的问题,希望能对你有帮助
 
with   (nolock)的用法很灵活   可以说只要有   from的地方都可以加   with   (nolock)   标记来取消产生意象锁,这里   可以用在   delete   update,select   以及   inner   join   后面的from里,对整个系统的性能提高都很有帮助
 
==========================
use master –必须在master数据库中创建
go

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_lockinfo]’) and OBJECTPROPERTY(id, N’IsProcedure’) = 1)
drop procedure [dbo].[p_lockinfo]
GO

/*–处理死锁

 查看当前进程,或死锁进程,并能自动杀掉死进程

 因为是针对死的,所以如果有死锁进程,只能查看死锁进程
 当然,你可以通过参数控制,不管有没有死锁,都只查看死锁进程

 感谢: caiyunxia,jiangopen 两位提供的参考信息

–邹建 2004.4–*/

/*–调用示例

 exec p_lockinfo
–*/
create proc p_lockinfo
@kill_lock_spid bit=1,  –是否杀掉死锁的进程,1 杀掉, 0 仅显示
@show_spid_if_nolock bit=1 –如果没有死锁的进程,是否显示正常进程信息,1 显示,0 不显示
as
declare @count int,@s nvarchar(1000),@i int
select id=identity(int,1,1),标志,
 进程ID=spid,线程ID=kpid,块进程ID=blocked,数据库ID=dbid,
 数据库名=db_name(dbid),用户ID=uid,用户名=loginame,累计CPU时间=cpu,
 登陆时间=login_time,打开事务数=open_tran, 进程状态=status,
 工作站名=hostname,应用程序名=program_name,工作站进程ID=hostprocess,
 域名=nt_domain,网卡地址=net_address
into #t from(
 select 标志=’死锁的进程’,
  spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
  status,hostname,program_name,hostprocess,nt_domain,net_address,
  s1=a.spid,s2=0
 from master..sysprocesses a join (
  select blocked from master..sysprocesses group by blocked
  )b on a.spid=b.blocked where a.blocked=0
 union all
 select ‘|_牺牲品_>’,
  spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
  status,hostname,program_name,hostprocess,nt_domain,net_address,
  s1=blocked,s2=1
 from master..sysprocesses a where blocked<>0
)a order by s1,s2

select @count=@@rowcount,@i=1

if @count=0 and @show_spid_if_nolock=1
begin
 insert #t
 select 标志=’正常的进程’,
  spid,kpid,blocked,dbid,db_name(dbid),uid,loginame,cpu,login_time,
  open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
 from master..sysprocesses
 set @count=@@rowcount
end

if @count>0
begin
 create table #t1(id int identity(1,1),a nvarchar(30),b Int,EventInfo nvarchar(255))
 if @kill_lock_spid=1
 begin
  declare @spid varchar(10),@标志 varchar(10)
  while @i<=@count
  begin
   select @spid=进程ID,@标志=标志 from #t where id=@i
   insert #t1 exec(‘dbcc inputbuffer(‘+@spid+’)’)
   if @标志=’死锁的进程’ exec(‘kill ‘+@spid)
   set @i=@i+1
  end
 end
 else
  while @i<=@count
  begin
   select @s=’dbcc inputbuffer(‘+cast(进程ID as varchar)+’)’ from #t where id=@i
   insert #t1 exec(@s)
   set @i=@i+1
  end
 select a.*,进程的SQL语句=b.EventInfo
 from #t a join #t1 b on a.id=b.id
end
go


 

FCKeditor的全局API

来源:http://www.cnblogs.com/xiaotaoliang/archive/2007/05/15/746851.html
FCKeditor offers a complete Javascrīpt API so you can interact with it once the editor is loaded and running.


Retrieving an editor instanceOnce loaded, the editor registers a global object called FCKeditorAPI. This object offers the entry point to interact with any editor instance placed in a page (you can have more than one). When placing the editor in the page, you give it an “instance name”. So, to retrieve it, you must simply call the FCKeditorAPI.GetInstance method. For example:

var ōEditor = FCKeditorAPI.GetInstance(‘InstanceName’) ;


The returned object
The GetInstance method returns the main FCKeditor object that gives the necessary bridge to interact with it. This is a list of properties and methods of this object:


* Descrīption = string
* EditMode = Integer
* Name = string
* Status = Integer
* function AttachToOnSelectionChange(functionPointer)
* function CleanAndPaste(html)
* function CreateElement(tag)
* function CreateLink(url)
* function ExecOnSelectionChange() //Fires OnSelectionChange event in event manager
* function ExecOnSelectionChangeTimer()
* function ExecuteNamedCommand(commandName, commandParameter)
* function ExecuteRedirectedNamedCommand(commandName, commandParameter)
* function Focus()
* function GetHTML(format) // doesnt work. Use GetXHTML instead.
* function GetNamedCommandState(commandName)
* function GetNamedCommandValue(commandName)
* function GetXHTML(format)
* function Initializebehavīors()
* function InsertElement(element)
* function InsertElementAndGetIt(e)
* function InsertHtml(html)
* function IsDirty();
* function MakeEditable()
* function OnDoubleClick(element)
* function Paste()
* function PasteAsPlainText()
* function PasteFromWord()
* function Preview()
* function RegisterDoubleClickHandler(handlerFunction, tag)
* function ResetIsDirty();
* function SetHTML(html, forceWYSIWYG)
* function SetStatus()
* function ShowContextMenu(x, y)
* function SwitchEditMode()
* function UpdateLinkedField()


EventsOnce the editor loading is complete and it is ready to use (and interact with Javascrīpt), a standard function is called in the page that contains the editor, if the function is defined. This function must be named “FCKeditor_OnComplete” and receives the related editor instance as the parameter. Using it, you can execute any initial code that makes the initial interaction with the editor. This is a declaration example:


function FCKeditor_OnComplete( editorInstance )
{
alert( editorInstance.Name ) ;
}

Apart the above standard event, every FCKeditor instance has a “Event” object that can be used to listen for events to be fired. For example, the following code listens for the “OnSelectionChange” to execute custom code:


var counter = 0 ;
function DoSomething( editorInstance )
{
window.document.title = editorInstance.Name + ‘ : ‘ + ( ++counter ) ;
}
function FCKeditor_OnComplete( editorInstance )
{
editorInstance.Events.AttachEvent( ‘OnSelectionChange’, DoSomething ) ;
}

Note that every callback function receives the editor instance as a parameter.

The following is the list of events available:

OnSelectionChange: fired when the actual selection in the editor area changes (by selection I mean the cursor position too… it changes on key strokes). Note: In IE6, this event does not fire on every keystroke, but only on some random keystrokes. Handy!

OnAfterSetHTML: fired once the HTML is loaded in the editor (including when changing views).

OnStatusChange: fired when the editor status changes. The following constants are also available globally in the page: FCK_STATUS_NOTLOADED, FCK_STATUS_ACTIVE and FCK_STATUS_COMPLETE.

OnPaste: fired when something is pasted in the editor

大量ICON图标下载网站汇总

图标文件是我们经常用到的一种小图片,它可以美化你的系统,也是网站或博客设计中不可缺少的一种元素,尤其在web2.0盛行的今天。但由于尺寸较 小、象素要求较高、文件格式特殊而使一些非专业人士制作起来相当费时费力,且不容易达到需求的效果。今天,秦爱为大家准备了大量的icon图标,供你免费 下载,其中有专门的ICON图标搜索引擎,也有大量的专业ICON图标下载网站,还有几个在线制作工具。
2个图标搜索引擎

iconfinder 提供的图标搜索比较有特色,提供128×128的大图预览,也可以直接下载。它还提供标签云,你可以直接从标签中直接查找相关图标文件。个人感觉,图标可以少了些,也可能我搜得比较偏吧。

iconlet 也是一款专门的图标搜索引擎,没有大图显示,没有标签云,完全一个垂直的搜索引擎。相比iconfinder而言,它的搜索结果要丰富许多,提供的图标尺寸大多是16×16像素的。

36个ICON图标下载网站 我就不一一介绍了,这些网站大体提供了免费和收费两种,我这里只列出他们免费的地址,你可以点开后看图下载。 4个手工在线制作ICO图标的网站

favicon  在线制作,不需要注册。

Online Icon Maker  通过上传图片制作ico和icon图标,另有图库备用

FavIcon  可以制作透明效果的ico图标,也是通过上传图片来进行转换。

Favicon Editor  通过上传图片转换ICO图标。

www.000webhost.com