Ian*_*oyd 5 sql-server sql-server-2008-r2 database-deadlocks
我有两个假设的问题:
UPDATE BankAccounts SET HomePhone = '+1 252-555-0912'
WHERE AccountNumber = 14400000619
Run Code Online (Sandbox Code Playgroud)
和
SELECT * FROM BankAccounts
WHERE HomePhone = '555-1212'
Run Code Online (Sandbox Code Playgroud)
在没有额外索引的假设表上:
CREATE TABLE BankAccounts
(
AccountNumber bigint NOT NULL PRIMARY KEY CLUSTERED,
FirstName nvarchar(50) NOT NULL,
MiddleName nvarchar(50) NULL,
LastName nvarchar(50) NOT NULL,
HomePhone varchar(50) NULL,
IsClosed tinyint DEFAULT 0
)
Run Code Online (Sandbox Code Playgroud)
一切都会很棒.如果我添加一个索引HomePhone:
CREATE INDEX IX_BankAccounts_HomePhone ON BankAccounts
( HomePhone)
Run Code Online (Sandbox Code Playgroud)
现在我的SELECT陈述可能是一个僵局的受害者:
Tranasction(进程ID 169)在锁资源上与另一个进程陷入僵局,并被选为死锁牺牲品.重新运行该交易.
共同的建议是:
除了这种情况:
消除这种死锁的长期解决方案是什么?
我正在考虑将我的交易隔离级别更改为READ UNCOMMITTED(即消除完整性),但由于我实际上正在处理金融系统,因此我犹豫是否允许客户两次撤回其全部余额.
我能找到的唯一其他解决方案来自KB Article 83252:
SQL Server技术公告 - 如何解决死锁
...死锁是无法避免的.这就是为什么前端应用程序应该设计为处理死锁的原因.
在设计良好的应用程序中,前端应用程序应捕获1205错误,重新连接到SQL Server,然后重新提交事务.
我猜这说:"不能赢;不要试试"
还要别的吗?
如果将 替换为列列表(或考虑所有列),然后将它们作为d columnsSELECT *添加到索引中,那么查询将不需要查询聚集索引来完成。然后总是可以运行完成。INCLUDESELECTSELECT
如果您不想这样做,那么我不会改变整个隔离级别,而是考虑锁定提示是否合适SELECT。无论是适当的提示NOLOCK还是READPAST您需要仔细考虑的内容(在理想的情况下,将有一种方法来指定READPAST但获取有关是否实际发生任何跳过行的信息)。
当然,也可以考虑SNAPSHOT 隔离(如果没有锁,就不会有死锁)。
(贪图惩罚的人也可以考虑TABLOCKX在SELECT语句上使用。它将防止死锁并确保您读取一行(如果存在),但会造成并发性的巨大损失)
| 归档时间: |
|
| 查看次数: |
17791 次 |
| 最近记录: |