Параллельная обработка транзакций Sql - PullRequest
4 голосов
/ 17 апреля 2010

Предположим, я собираюсь начать проект с использованием ASP.NET и SQL Server 2005. Мне нужно разработать требование параллелизма для этого приложения. Я планирую добавить столбец TimeStamp в каждой таблице. При обновлении таблиц я проверю, чтобы столбец TimeStamp был таким же, как он был выбран.

Будет ли этого подхода достаточно? Или есть ли недостатки этого подхода при любых обстоятельствах?

Пожалуйста, совет.

Спасибо

Lijo

Ответы [ 4 ]

4 голосов
/ 18 апреля 2010

Прежде всего то, что вы описываете в своем вопросе, на мой взгляд, лучший способ для приложения ASP.NET с MS SQL в качестве базы данных. В базе данных нет блокировки. Он идеально подходит для постоянно отключенных клиентов , таких как веб-клиенты.

Как можно прочитать из некоторых ответов, в терминологии есть недоразумение. Мы все подразумеваем использование Microsoft SQL Server 2008 или выше для хранения базы данных. Если вы откроете в документации по MS SQL Server 2008 тему «версия строки (Transact-SQL)», вы найдете следующее:

" отметка времени является синонимом rowversion тип данных и зависит от поведение синонима типа данных. "… Msgstr "Синтаксис timestamp устарел. Эта функция будет удалена в будущая версия Microsoft SQL Сервер. Избегайте использования этой функции в новые разработки и планируют изменить приложения, которые в настоящее время используют эта функция. "

Итак, timestamp тип данных - это синоним типа данных rowversion для MS SQL. Он содержит 64-битный счетчик, который существует внутри каждой базы данных и может рассматриваться как @@ DBTS . После изменения одной строки в одной таблице базы данных счетчик будет увеличиваться.

Когда я читаю ваш вопрос, я читаю «TimeStamp» как имя столбца типа rowversion data. Я лично предпочитаю имя RowUpdateTimeStamp . В AzManDB (см. Microsoft Authorization Manager с Store as DB) я мог видеть такое имя. Иногда использовались также ChildUpdateTimeStamp для отслеживания иерархических RowUpdateTimeStamp (с учетом триггеров).

Я реализовал этот подход в своем последнем проекте и буду очень счастлив. Обычно вы делаете следующее:

  1. Добавьте RowUpdateTimeStam p столбца к каждой таблице вашей базы данных с типом rowversion (в Microsoft SQL Management Studio это будет выглядеть как timestamp , что то же самое).
  2. Вы должны построить все свои запросы SQL SELECT для отправки результатов клиенту так, чтобы вы отправляли дополнительное значение RowVersion вместе с основными данными. Если у вас есть SELECT с JOINT, вы должны отправить RowVersion максимального RowUpdateTimeStamp из обеих таблиц, например
SELECT s.Id AS Id
    ,s.Name AS SoftwareName
    ,m.Name AS ManufacturerName
    ,CASE WHEN s.RowUpdateTimeStamp > m.RowUpdateTimeStamp
          THEN s.RowUpdateTimeStamp 
          ELSE m.RowUpdateTimeStamp 
     END AS RowUpdateTimeStamp 
FROM dbo.Software AS s
    INNER JOIN dbo.Manufacturer AS m ON s.Manufacturer_Id=m.Id

Или выполните приведение данных следующим образом

SELECT s.Id AS Id
    ,s.Name AS SoftwareName
    ,m.Name AS ManufacturerName
    ,CASE WHEN s.RowUpdateTimeStamp > m.RowUpdateTimeStamp
          THEN CAST(s.RowUpdateTimeStamp AS bigint)
          ELSE CAST(m.RowUpdateTimeStamp AS bigint)
     END AS RowUpdateTimeStamp 
FROM dbo.Software AS s
    INNER JOIN dbo.Manufacturer AS m ON s.Manufacturer_Id=m.Id

для хранения RowUpdateTimeStamp как bigint , что соответствует ulong типу данных C #. Если вы делаете OUTER JOINTs или JOINTs из многих таблиц, конструкция MAX(RowUpdateTimeStamp) из всех таблиц будет выглядеть немного более сложной. Поскольку MS SQL не поддерживает такие функции, как MAX (a, b, c, d, e), соответствующая конструкция может выглядеть следующим образом:

(SELECT MAX(rv)
 FROM (SELECT table1.RowUpdateTimeStamp AS rv
      UNION ALL SELECT table2.RowUpdateTimeStamp
      UNION ALL SELECT table3.RowUpdateTimeStamp
      UNION ALL SELECT table4.RowUpdateTimeStamp
      UNION ALL SELECT table5.RowUpdateTimeStamp) AS maxrv) AS RowUpdateTimeStamp
  1. Все отключенные клиенты (веб-клиенты) получают и хранят не только некоторые строки данных, но и RowVersion (тип ulong ) строки данных.
  2. В одной попытке изменить данные от отключенного клиента ваш клиент должен отправить RowVersion , соответствующий исходным данным, на сервер. Хранимая процедура spSoftwareUpdate может выглядеть как
CREATE PROCEDURE dbo.spSoftwareUpdate
    @Id int,
    @SoftwareName varchar(100),
    @originalRowUpdateTimeStamp bigint, -- used for optimistic concurrency mechanism
    @NewRowUpdateTimeStamp bigint OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    -- ExecuteNonQuery() returns -1, but it is not an error
    -- one should test @NewRowUpdateTimeStamp for DBNull
    SET NOCOUNT ON;

    UPDATE dbo.Software
    SET Name = @SoftwareName
    WHERE Id = @Id AND RowUpdateTimeStamp <= @originalRowUpdateTimeStamp

    SET @NewRowUpdateTimeStamp = (SELECT RowUpdateTimeStamp
                                  FROM dbo.Software
                                  WHERE (@@ROWCOUNT > 0) AND (Id = @Id));
END

Код хранимой процедуры dbo.spSoftwareDelete выглядит так же. Если вы не включите NOCOUNT, вы можете создать DBConcurrencyException , автоматически генерируемый во многих сценариях. Visual Studio дает вам возможность использовать оптимистичный параллелизм, такой как флажок «Использовать оптимистичный параллелизм» в дополнительных параметрах TableAdapter или DataAdapter.

.

Если вы посмотрите на dbo.spSoftwareUpdate хранимую процедуру carful, вы обнаружите, что я использую RowUpdateTimeStamp <= @originalRowUpdateTimeStamp в WHERE вместо RowUpdateTimeStamp = @originalRowUpdateTimeStamp. Я делаю это потому, что значение @originalRowUpdateTimeStamp, которое имеет клиент, обычно составляется как MAX(RowUpdateTimeStamp) из нескольких таблиц. Так может быть, что RowUpdateTimeStamp < @originalRowUpdateTimeStamp. Либо вы должны использовать строгое равенство = и воспроизвести здесь тот же сложный оператор JOIN, который вы использовали в операторе SELECT, либо использовать конструкцию <= </strong>, подобную мне, и оставаться точно такой же безопасной, как и раньше.

Кстати, можно построить очень хорошее значение для ETag на основе RowUpdateTimeStamp, который может отправлять в заголовке HTTP клиенту вместе с данными. С ETag вы можете реализовать интеллектуальное кэширование данных на стороне клиента.

Я не могу написать здесь весь код, но вы можете найти много примеров в Интернете. Я хочу лишь еще раз повторить, что, по моему мнению, использование оптимистичного параллелизма на основе rowversion является лучшим способом для большинства сценариев ASP.NET .

2 голосов
/ 17 апреля 2010

В SQL Server рекомендуемый подход к типу ситуации - создать столбец типа 'rowversion' и использовать его, чтобы проверить, изменилось ли какое-либо из полей в этой строке.

SQL Server гарантирует, что если какое-либо значение в строке изменится (или будет вставлена ​​новая строка), его столбец версии строки будет автоматически обновлен до другого значения. Позволить базе данных обрабатывать это для вас гораздо надежнее, чем пытаться сделать это самостоятельно.

В ваших операторах обновления вам просто нужно добавить предложение where, чтобы проверить, что значение rowversion такое же, как и при первом получении строки. Если нет, то кто-то другой изменил строку (то есть: она грязная)

Также с этой страницы:

Синтаксис метки времени устарел. Эта функция будет удалена в будущая версия Microsoft SQL Сервер. Избегайте использования этой функции в новые разработки и планируют изменить приложения, которые в настоящее время используют эта функция.

1 голос
/ 17 апреля 2010

Я не уверен, что параллелизм должен обрабатываться в базе данных следующим образом. Сама база данных должна иметь возможность управлять изоляцией и поведением транзакций, но поведение потоков должно выполняться в коде.

0 голосов
/ 17 апреля 2010
Я бы сказал, что предложение

rowversion верное, но разочаровывает тот факт, что отметка времени скоро устареет. Некоторые из моих старых приложений используют это по разным причинам, а затем проверяют параллелизм.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...