Таблица блоков медленных транзакций SQL

У меня очень медленная транзакция sql, которая вставляет новые строки в таблицу. Все другие запросы «выбора» из других подключений ждут, пока эта транзакция разблокирует таблицу.

Можно ли получить старые строки из таблицы, пока работает первая транзакция?

SQLExpress 2008 R2. Например:

    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, которая вставляет новые строки в таблицу. Все другие запросы «выбора» из других подключений ждут, пока эта транзакция разблокирует таблицу.

Можно ли получить старые строки из таблицы, пока работает первая транзакция?

SQLExpress 2008 R2. Например:

    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.


person user879096    schedule 04.08.2011    source источник
comment
Вы можете использовать табличные подсказки, такие как SELECT (columns) FROM dbo.TableName WITH (NOLOCK) .... — см. в электронной документации MSDN о табличных подсказках - у них есть и другие недостатки, о которых нужно знать   -  person marc_s    schedule 04.08.2011


Ответы (1)


Одной из быстрых карточек «выйти из тюрьмы» является включение чтения зафиксированного моментального снимка в базе данных, см. Выбор уровней изоляции на основе управления версиями строк, также упомянутых в разделе В тупике!. Когда RCSI включен в базе данных, ваш щелчок по кнопке 2 будет делать именно то, что вы хотите: он будет читать старую версию строки, не дожидаясь фиксации кнопки 1.

Чтобы включить RCSI, просто запустите это один раз:

ALTER DATABASE [test]  SET READ_COMMITTED_SNAPSHOT ON;

Конечно, бесплатного обеда не бывает: включение управления версиями строк потребует затрат на ввод-вывод и размер базы данных tempdb. См. раздел Использование ресурсов управления версиями строк. Для экземпляра Express не будет ощутимого воздействия.

person Remus Rusanu    schedule 04.08.2011
comment
Я читал про подсказку READPAST: SELECT COUNT(*) FROM Cards (READPAST), кажется, она позволит считать только старые строки. - person user879096; 04.08.2011
comment
READPAST также будет работать, но я настоятельно рекомендую вместо этого включить read_committed_snpashot. - person Remus Rusanu; 04.08.2011