我有两个假设的查询:
UPDATE BankAccounts SET HomePhone = '+1 252-555-0912'
WHERE AccountNumber = 14400000619
和
SELECT * FROM BankAccounts
WHERE HomePhone = '555-1212'
在没有额外索引的假设表上:
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
)
一切都会很好。如果我在以下位置添加索引HomePhone
:
CREATE INDEX IX_BankAccounts_HomePhone ON BankAccounts
( HomePhone)
现在我的SELECT
陈述可能成为僵局的受害者:
Tranasction(进程 ID 169)与另一个进程在锁资源上死锁,并已被选为死锁牺牲品。重新运行事务。
常见的建议是:
- 以相同的顺序访问表
- 尽可能缩短交易时间
除了这种情况:
- 我正在以相同的顺序访问(一个)表(1 选择 1 是 1)
- 交易是一个单一的声明;我不能比那更短
消除这种死锁的长期解决方案是什么?
我正在考虑将我的交易隔离级别更改为READ UNCOMMITTED
(即消除完整性),但因为我实际上正在处理一个金融系统,所以我很犹豫是否允许客户两次提取他的全部余额。
我能找到的唯一其他解决方案来自知识库文章 83252:
SQL Server 技术公告 - 如何解决死锁
...死锁无法避免。这就是为什么应该设计前端应用程序来处理死锁。
在设计良好的应用程序中,前端应用程序应捕获 1205 错误,重新连接到 SQL Server,然后重新提交事务。
我猜这是在说:“不能赢;不要尝试”
还要别的吗?