赞
踩
对应到SQL Server中,当在两个或多个任务中,如果每个任务锁定了其他任务试图锁定的资源,此时会造成这些任务永久阻塞,从而出现死锁;这些资源可能是:单行(RID,堆中的单行)、索引中的键(KEY,行锁)、页(PAG,8KB)、区结构(EXT,连续的8页)、堆或B树(HOBT) 、表(TAB,包括数据和索引)、文件(File,数据库文件)、应用程序专用资源(APP)、元数据(METADATA)、分配单元(Allocation_Unit)、整个数据库(DB)。
使用WITH(NOLOCK) 避免锁竞争。从WITH(NOLOCK) 来讲,它的目的是允许脏读,不锁定表,以达到快速查询的目的;SELECT查询时未使用WITH(NOLOCK)会产生共享锁,且在查询后立即使用了DELETE 删除此数据,则会变成独占锁;如果同一个seller在短时间内重复操作两次可能会引起两个事务竞争,产生死锁。在允许脏读的业务中,尤其是对同一条数据存在Select 和 UPDATE/DELETE/INSERT 的时候,就容易导致死锁问题;由于SQL SERVER 的强大功能,在查询数据的还可以做一些业务逻辑逻辑,这就容易发生在SELECT 之后进行UPDATE/DELETE/INSERT操作的可能性,就容易导致死锁问题,所以当我们在允许脏读的业务场景下,尽可能的加上WITH(NOLOCK),它也可以提高查询速度。使用这种方式避免死锁。
使用临时表修复死锁问题,首先清楚一个条件,就是在进行UPDATE/DELETE/INSERT操作,会产生排他锁,此操作会锁住要操作的数据。尤其是在Update 的时候,我们又INNER JOIN 关联查询了其他数据,极有可能导致死锁,请看如下这段sql:
UPDATE TOP 100 X
SET X.ShipFromCountryCode = TT.ShipFromCountryCode_Real,
X.FastestDeliveryDays = TT.FastestDeliveryDays,
X.SlowestDeliveryDays = TT.SlowestDeliveryDays,
X.LastEditDate = GETDATE(), X.LastEditUser = '模拟测试'
FROM Table1 TT
INNER JOIN Table2 X
ON X.ItemNumber = TT.ItemNumber AND X.CompanyCode = XXX AND X.ShipToCountryCode = TT.ShipToCountryCode
WHERE X.ShipFromCountryCode <> TT.ShipFromCountryCode_Real
OR X.FastestDeliveryDays IS NULL OR X.FastestDeliveryDays <> TT.FastestDeliveryDays
OR X.SlowestDeliveryDays IS NULL OR X.SlowestDeliveryDays <> TT.SlowestDeliveryDays
针对这段sql 产生死锁,我们可以做出如下优化考虑:
减少事务,减少事务持续。死锁简单来说是,事务越大,事务持续时间越长,越容易死锁;我们可以优化sql 的执行速度,避免一条语句执行过长。优化sql 执行速度的方式就有很多了,可以从索引,查询方式,筛选条件,查询参数等等入手;同时还可以在代码中进行优化,比如使用缓存来减少db查询,在代码中控制多线程顺序性访问,在代码中控制查询参数和条件筛选量,在代码中控制业务以保证单个method事务简短等等。
整体上来讲,尽可能避免死锁的发生,就是要减少查询范围,减少操作数据数量,避免锁冲突,是否允许脏读,减少UPDATE/DELETE/INSERT操作,减少SQL 逻辑,避免互斥访问。可以参考如下几个点:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。