5

私は2つの架空のクエリを持っています:

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は1です)
  • トランザクションは単一のステートメントです。それより短くすることはできません

このようなデッドロックを解消するための長期的な解決策は何ですか?

トランザクション分離レベルをに変更する(つまり、整合性を排除する)ことを検討してREAD UNCOMMITTEDいましたが、実際には金融システムを扱っているため、顧客が残高全体を2回引き出すことを躊躇しています。

私が見つけることができる他の唯一の解決策はKBArticle83252から来ています:

SQLServerテクニカルブリテン-デッドロックを解決する方法

...デッドロックは避けられません。そのため、フロントエンドアプリケーションはデッドロックを処理するように設計する必要があります。

適切に設計されたアプリケーションでは、フロントエンドアプリケーションは1205エラーをトラップし、SQL Serverに再接続してから、トランザクションを再送信する必要があります。

私が推測しているのは、 「勝てない、やってはいけない」ということです。

他に何か?

4

2 に答える 2

4

SELECT *を列リストに置き換えて(またはすべての列を考慮して)、それらをINCLUDEdとしてインデックスに追加すると、SELECTクエリはクラスター化インデックスをクエリして完了する必要がなくなります。その後、SELECT缶は常に完了するまで実行できます。

それを望まない場合は、分離レベル全体を変更するのではなく、のロックのヒントSELECTが適切かどうかを検討します。適切なヒントが慎重に検討する必要があるかどうかNOLOCKREADPAST理想的な世界ではREADPAST、行のスキップが実際に発生したかどうかを指定して情報を取得する方法があります)。

もちろん、SNAPSHOT 分離も考慮される場合があります(ロックがない場合、デッドロックはありません)。


(罰のための大食いはTABLOCKXSELECTステートメントでの使用を検討する場合もあります。デッドロックを防ぎ、行が存在する場合は、同時実行性に大きなペナルティを課して、行を確実に読み取るようにします)

于 2013-01-28T14:46:51.303 に答える
3

勝つことはできません。試さないでください

それは正しい。おそらく読み取り/書き込みデッドロックが発生しています(デッドロックグラフは、私たちの推測にすぎません)。逆順のアクセスは、正しいことをしている(つまり、正しいインデックスを持っている)という理由だけで発生します。別のキーにアクセスした場合(1つの電話を検索し、別の電話を更新した場合)でも、ハッシュの衝突により確率のゲームをプレイしています。

デッドロックを受け入れるか、スナップショットアイソレーションモデルに頼ることができます。

于 2013-01-28T15:20:10.090 に答える