web-dev-qa-db-ja.com

MS SQL Serverでテーブル全体をロックしないようにSQL挿入または更新、あるいはその両方を行う方法

DBの仕事は初心者なので、基本的な質問をお待ちください。ローカルコンピューターでSQL Server 2014を実行しています。さまざまなアプローチをテストするための小さなテーブルと基本的なクライアントアプリケーションがあります。 _INSERT INTO_とUPDATEステートメントの両方で、テーブルロックのように見えるものを取得しています。クライアントは、次のコードを持つASP.NETアプリケーションです。

_OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();
_

このコードを実行してから、管理スタジオから_SELECT * FROM LAYOUTSv2_を実行します。どちらの場合も、クライアントスレッドが一時停止しているとき(つまり、コミット/ロールバックの前)、SELECTクエリはコミット/ロールバックが発生するまでハングします。

テーブルには、主キーとして割り当てられたフィールドLAYOUTS_keyがあります。プロパティウィンドウでは、ページロックと行ロックの両方が許可されており、クラスター化されていることを示しています。テーブルのロックエスカレーション設定は無効です...私は、テーブルとAUTOの他の利用可能な設定の両方を変更せずに試しました。私はSELECT ... WITH (NOLOCK)を試しましたが、すぐに結果が返されますが、十分注意してください here と他の場所では、私がやるべきことではありません。 ROWLOCKINSERTステートメントの両方にUPDATEヒントを付けようとしましたが、何も変更されていません。

私が探している動作は次のとおりです。INSERTをコミットする前に、他のスレッドからのクエリは、INSERTedされている行を除くすべての行を読み取ります。他のスレッドからのUPDATEクエリをコミットする前に、UPDATEedである行の開始バージョンを読み取ります。これを行う方法はありますか?ユースケースを明確にするために他の情報を提供する必要がある場合は、お知らせください。ありがとう。

13
John Riehl

「テーブル全体」をロックしていない可能性があります。

テーブルの行をロックしていますが、SELECT * FROM LAYOUTSv2はテーブル全体を読み取ろうとするため、必ずそのロックによってブロックされます。

挿入の場合、READPASTヒントを指定して、ロックされた行をスキップすることができますが、UPDATEの場合に希望の結果が得られません(行をスキップして再度読み取りません)行の開始バージョン)。

読み取りコミットスナップショット分離 のデータベースを構成する場合、これにより、両方のケースで望ましい効果が得られます(tempdbの使用が増える代わりに)。

10
Martin Smith

Insert文とupdate文は、行レベルのロックを作成することになっています。ただし、トランザクションのロック数が5,000以上の場合、ロックのエスカレーションが発生し、テーブルレベルのロックが作成されます。下記を参照してください。

https://technet.Microsoft.com/en-us/library/ms184286(v = sql.105).aspx

7
Suraj