1

テーブルに新しい行を挿入する非常に遅いSQLトランザクションがあります。別の接続からの他のすべての「選択」クエリは、このトランザクションがテーブルのロックを解除するのを待ちます。

最初のトランザクションが機能している間に、テーブルから古い行をフェッチすることは可能ですか?

SqlExpress2008R2。例:

    private void button1_Click(object sender, EventArgs e)
    {
        System.Threading.Thread t = new System.Threading.Thread(
            delegate()
            {
                var conn = new SqlConnection(@"Data Source=ARTNB\SQLEXPRESS;Initial Catalog=test;User ID=**;Password=******");
                conn.Open();
                var cmd = conn.CreateCommand();
                var tr = conn.BeginTransaction( IsolationLevel.RepeatableRead, "test");
                cmd.Transaction = tr;
                cmd.CommandText = @"INSERT INTO Cards (SerialNumber,OperationID,TariffID,RequestTime,State,AgentInfo) VALUES('1213','345',13, GETDATE(),1,'')";
                cmd.ExecuteNonQuery();
                //very slow transaction
                System.Threading.Thread.Sleep(300000);
                tr.Commit();
                conn.Close();
            });
        t.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        var conn = new SqlConnection(@"Data Source=ARTNB\SQLEXPRESS;Initial Catalog=test;User ID=**;Password=******");
        conn.Open();
        var cmd = conn.CreateCommand();
        var tr = conn.BeginTransaction(IsolationLevel.RepeatableRead, "test2");
        cmd.Transaction = tr;
        cmd.CommandText = @"SELECT COUNT(*) FROM Cards";
        var r = cmd.ExecuteReader();
        r.Read();
        r.Close();
        tr.Commit();
        conn.Close();
    }

button2_Clickメソッドは、行をすぐにフェッチしません。テーブルに新しい行を挿入する非常に遅いSQLトランザクションがあるため、コミットを待機します。別の接続からの他のすべての「選択」クエリは、このトランザクションがテーブルのロックを解除するのを待ちます。

最初のトランザクションが機能している間に、テーブルから古い行をフェッチすることは可能ですか?

SqlExpress2008R2。例:

    private void button1_Click(object sender, EventArgs e)
    {
        System.Threading.Thread t = new System.Threading.Thread(
            delegate()
            {
                var conn = new SqlConnection(@"Data Source=ARTNB\SQLEXPRESS;Initial Catalog=test;User ID=**;Password=******");
                conn.Open();
                var cmd = conn.CreateCommand();
                var tr = conn.BeginTransaction( IsolationLevel.RepeatableRead, "test");
                cmd.Transaction = tr;
                cmd.CommandText = @"INSERT INTO Cards (SerialNumber,OperationID,TariffID,RequestTime,State,AgentInfo) VALUES('1213','345',13, GETDATE(),1,'')";
                cmd.ExecuteNonQuery();
                //very slow transaction
                System.Threading.Thread.Sleep(300000);
                tr.Commit();
                conn.Close();
            });
        t.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        var conn = new SqlConnection(@"Data Source=ARTNB\SQLEXPRESS;Initial Catalog=test;User ID=**;Password=******");
        conn.Open();
        var cmd = conn.CreateCommand();
        var tr = conn.BeginTransaction(IsolationLevel.RepeatableRead, "test2");
        cmd.Transaction = tr;
        cmd.CommandText = @"SELECT COUNT(*) FROM Cards";
        var r = cmd.ExecuteReader();
        r.Read();
        r.Close();
        tr.Commit();
        conn.Close();
    }

button2_Clickメソッドは、行をすぐにフェッチするのではなく、button1_Clickスレッドでコミットを待機します。

4

1 に答える 1

5

「脱獄」カードの1つは、データベースでコミットされたスナップショットの読み取りを有効にすることです。「行のバージョン管理に基づく分離レベルの選択」を参照してください。これについては、デッドロックについても説明しています。。データベースでRCSIが有効になっている場合、butonn2クリック読み取りは希望どおりに実行されます。つまり、button1がコミットするのを待たずに、古いバージョンの行を読み取ります。

RCSIを有効にするには、これを1回実行するだけです。

ALTER DATABASE [test]  SET READ_COMMITTED_SNAPSHOT ON;

もちろん、フリーランチはありません。行のバージョン管理を有効にすると、tempdbのIOとサイズにコストがかかります。行のバージョン管理リソースの使用法を参照してください。Expressインスタンスの場合、測定可能な影響はありません。

于 2011-08-04T18:07:35.127 に答える