「nolock」なのでロックしないっしょ~と思いがちですが、その認識が間違っていたのでメモ。
SQLServerのロックについて
ロック モード
https://technet.microsoft.com/ja-jp/library/ms175519(v=sql.105).aspx
ロックの互換性
https://technet.microsoft.com/ja-jp/library/ms186396(v=sql.105).aspx
まずはロックについて。ロックにもいろいろ種類があるよっていう話と、同時に同一リソースにかけられるロックもあるよという話。
ここを一読すればだいたいつかめると思います。
名前忘れちゃったのですが、前に読んだ書籍に書いてあった、旗のイメージでロックを考えると分かりやすかったです。
Aの旗は同時に2本以上たてられるけど、Bの旗は1本しかたてられない。AとCの旗は一緒に立てられるけど、Dの旗は他のどの旗とも一緒には立てられない、、、みたいな。
with(nolock)をつけると何がおきているか
通常のSELECT文を発行すると、S-lock(共有ロック)が取得されます。こちらはdeleteなど発行した時のロック(X-lock)と競合するので、該当テーブルが更新中の場合はSELECTが待たされることになります。
with(nolock)をつけたSELECT文は、Sch-S lock(スキーマ安定度ロック)が取得されます。こちらはX-lockと競合しないので、更新中のテーブルでもSELECTできます。(※ダーティリード)
ということで、with(nolock)をつける=取得するロックをSch-Sロックにするということですね。
このロックはX-LockやU-Lockと競合しないため、確かにnolockなのですが、、、このSch-Sロックとも競合してしまう強力なロックがあります。
それがSch-M lock(スキーマ修正ロック)です。
インデックス付Viewを作成するとき(schema bindngしたViewにインデックス張るとき)や、transaction内でtruncateしたときなど、
Sch-Mロックが取得されます。
このSch-Mロックがかかると、該当リソースへのアクセスができなくなってしまうため、長時間Sch-Mロックが取得され続けるとタイムアウトエラーが頻発してしまいます。
他にもSch-Mロックが取得されるケースは存在するので、稼動しているDBに対してオンラインで何かしらの操作をする場合には、その操作によって取得されるロックの種類と、そのロックが取得されることによる影響をしっかりと開発環境で検証しておく必要があります。
うっかりSch-Mロックをかけてしまうと、(Sch-Mロックは長時間取得されるような重い操作が多いので)たっぷりタイムアウトエラーが発生しますので注意が必要です。