死锁——这真的有帮助吗?
Posted
技术标签:
【中文标题】死锁——这真的有帮助吗?【英文标题】:Deadlocks - Will this really help? 【发布时间】:2010-07-30 17:56:56 【问题描述】:所以我有一个查询让我一直陷入僵局。熟悉系统的人无法弄清楚存储过程为什么会死锁,但他们告诉我应该将其添加到其中:
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
这真的是一个有效的解决方案吗?那有什么作用?
【问题讨论】:
尽管人们可以比我更好地解释这些设置,但我会指出,READ UNCOMMITTED 具有您在启用它之前应该了解的后果。非常害怕在不了解会发生什么的情况下更改隔离级别。 哈哈,听起来像我以前工作的地方...这是那里任何 SQL 死锁或性能问题的第一个答案...没有分析,只需将其粘贴并提交:P跨度> 我宁愿你向我们展示死锁的查询。 :) 【参考方案1】:SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
这将导致系统返回不一致的数据,包括重复记录和丢失记录。在Previously committed rows might be missed if NOLOCK hint is used 或Timebomb - The Consistency problem with NOLOCK / READ UNCOMMITTED 阅读更多信息。
可以调查和修复死锁,如果您遵循正确的程序,这没什么大不了的。当然,进行脏读可能看起来更容易,但在此过程中,您将长时间坐着盯着您的总账并想知道为什么它确实不平衡借方和贷方。所以再读一遍,直到你真正理解这一点:DIRTY READs ARE INCONSISTENT READS。
如果你想要一张越狱卡,请打开snapshot isolation:
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
但请记住,快照隔离不会修复死锁,它只会隐藏死锁。正确调查死锁原因并进行修复始终是适当的措施。
【讨论】:
【参考方案2】:NOCOUNT 将阻止您的查询将行数返回给调用应用程序(即 1000000 行受影响)。
TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 将允许脏读,如 here. 所示
隔离级别可能会有所帮助,但您要允许脏读吗?
【讨论】:
我猜他因为某种原因陷入僵局,所以他没有!【参考方案3】:在查询中随机添加 SET
选项恐怕不太可能有帮助
SET NOCOUNT ON
对问题没有影响。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
将阻止您的查询获取共享锁。除了读取“脏”数据外,它还可能导致您的查询读取相同的行两次,或者根本不读取,这取决于正在发生的其他并发活动。
这是否会解决您的死锁问题取决于死锁的类型。如果问题是由于锁定请求的非线性排序而导致 2 个写入者死锁,则它根本不会产生任何影响。 (事务 1 更新 a 行,事务 2 更新 b 行,然后 tran 1 请求锁定 b,然后 tran 2 请求锁定 a)
你能发布有问题的查询和死锁图吗? (如果您使用的是 SQL 2005 或更高版本)
【讨论】:
【参考方案4】:最好的指南是:
http://technet.microsoft.com/es-es/library/ms173763.aspx
片段:
指定语句可以读取已经被其他人修改过的行 交易但尚未提交。
在 READ 上运行的事务 UNCOMMITTED 级别不发布共享 锁定以防止其他事务 从修改读取的数据 当前交易。阅读未提交 交易也不会被阻止 排他锁会阻止 读取行的当前事务 已修改但未修改的 由其他事务提交。什么时候 设置了这个选项,就可以 读取未提交的修改,其中 被称为脏读。中的价值观 数据可以更改,行可以 在数据集中出现或消失 交易结束前。 此选项的效果与 在所有表上设置 NOLOCK 事务中的 SELECT 语句。 这是限制最少的 隔离级别。
在 SQL Server 中,您还可以最小化 在保护的同时锁定争用 来自脏读的事务 未提交的数据修改使用 要么:
READ COMMITTED 隔离级别 与 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON。这 SNAPSHOT 隔离级别
.
【讨论】:
【参考方案5】:换一种思路,还有另外两个方面需要考虑,这可能会有所帮助。
1) 索引和SQL 使用的索引。表上使用的索引策略将影响受影响的行数。如果您使用唯一索引进行数据修改,您可能会减少死锁的机会。
一种算法 - 当然它不会在所有情况下都有效。 NOLOCK 的使用是有针对性的,而不是全球性的。
The "old" way:
UPDATE dbo.change_table
SET somecol = newval
WHERE non_unique_value = 'something'
The "new" way:
INSERT INTO #temp_table
SELECT uid FROM dbo.change_table WITH (NOLOCK)
WHERE non_unique_value = 'something'
UPDATE dbo.change_table
SET somecol = newval
FROM dbo.change_table c
INNER JOIN
#temp_table t
ON (c.uid = t.uid)
2) 交易持续时间 交易开放的时间越长,争用的可能性就越大。如果有办法减少记录保持锁定的时间,您可以减少发生死锁的机会。 例如,在代码开头执行尽可能多的 SELECT 语句(例如查找),而不是执行 INSERT 或 UPDATE,然后执行查找,然后执行 INSERT,然后执行另一个查找。 这是一个可以在“静态”表上使用 NOLOCK 提示进行选择的地方,这些表不会改变,从而减少代码的锁定“足迹”。
【讨论】:
以上是关于死锁——这真的有帮助吗?的主要内容,如果未能解决你的问题,请参考以下文章