Изоляция транзакций и чтение из нескольких таблиц в SQL Server Express и SQL Server 2005

У меня есть база данных с основной таблицей (назовем ее владельцем) и несколько вложенных таблиц с запасами (например, автомобили, книги и т. Д.).

Например:

  • Owner имеет столбцы: owner_id, name
  • Cars имеет столбцы: owner_id (foreign key), brand
  • Books имеет столбцы: owner_id (foreign key), title, author

Моя программа должна рассчитывать статистику, например, сколько владельцев BMW также владеет книгой о Гарри Поттере, используя различные сторонние библиотеки. Я хочу прочитать все строки из всех таблиц одновременно, а затем выполнить анализ в не SQL-код.

Я хочу прочитать все таблицы, используя отдельные Select * From X заявления. Я не могу использовать одно большое соединение, так как оно вернуло бы слишком много строк ((владельцы * автомобили * книги) вместо (владельцы + автомобили + книги)). Союз не сокращает это также, так как таблицы содержат различные столбцы различных типов.

Я поставил

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

но у меня все равно есть некоторые проблемы.

Если я подчеркиваю базу данных, выполняя два потока, один случайным образом вставляя или удаляя, а другой читая, я иногда получаю противоречивые результаты, например Cars были удалены между чтением Owners и читать Cars Таблица.

У меня есть несколько вопросов:

  1. Как правильно предотвратить изменение при чтении из нескольких таблиц одна за другой? Ни одна таблица не должна быть изменена, пока все не будут прочитаны.

    Я использую SQL Server 2005 (в сети) и SQL Server 2005 Express (локальный). Можно ли явно получить блокировки для нескольких таблиц одновременно?

  2. Если я запускаю свою локальную базу данных SQL Server Express, я не могу заставить ее работать независимо от того, что я делаю. Если я запускаю свою сетевую базу данных SQL Server 2005, я могу заставить ее работать (с некоторыми усилиями). Поддерживает ли SQL Server Express уровень изоляции транзакции SERIALIZABLE? Я считаю, что это должно. Различия могут быть связаны с медленным подключением к сети, но я не знаю.

    На моем локальном БД я не могу предотвратить изменения между чтениями. То есть один поток случайно удаляет случайного владельца (сначала автомобили, затем книги, затем владельца) или вставляет нового владельца (введите владельца, вставьте 2 машины, вставьте 2 книги). Другой поток читает с использованием:

    Begin Tran
    Select owner_id From Owner
    Select owner_id, brand From Cars
    Select owner_id, title, author From Books
    Commit Tran
    

    Независимо от того, что я делаю, иногда я получаю владельца с нулевым количеством автомобилей или нулевых книг. Это никогда не должно происходить, поскольку все вставки и удаления находятся в одной транзакции. Мне кажется, что экспресс-сервер не блокирует заявления владельца, машины и книги одновременно.

    На сетевом SQL Server 2005 он работает нормально, но это может быть из-за медленного соединения и, следовательно, более низкой вероятности одновременного выполнения.

  3. На моей локальной базе данных я начинаю каждую транзакцию с фиктивной Select из всех таблиц, чтобы предотвратить взаимоблокировку. Я не понимаю, почему это предотвращает взаимоблокировку, а не модификацию таблиц. Это не обязательно для сетевого SQL Server 2005.

В настоящее время я не могу сказать, неправильно ли я понял что-то об изоляции транзакции или это проблема различий между SQL Server Express и SQL Server 2005. Любая помощь или идеи будут с благодарностью.

2 ответа

Решение

Ваш выбор загрузки всех данных за один раз означает очень мало вариантов:

  • Используйте sp_getapplock для сериализации доступа через соответствующий код
  • Используйте TABLOCKX, HOLDLOCK для операций чтения в транзакции

У вас есть проблемы, потому что SET TRANSACTION ISOLATION LEVEL SERIALIZABLE влияет только на изоляцию замков: нужно контролировать продолжительность (HOLDLOCK) и гранулярность + режим (TABLOCKX)

Иногда я получаю противоречивые результаты,

Если в дальнейшем вы не будете выполнять пакетную обработку в базе данных, которая в противном случае не используется, лучше привыкнуть к определенным колебаниям, которые не будут иметь значения в любом случае.

Если у вас мало записей, изменения не будут иметь значения в абсолютных числах. В любом случае вы имеете дело со статистикой. Используйте READ COMMITED и устраняйте несоответствия, признавая, что набор данных не является статичным.

Все остальное полностью убьет производительность.

ИЛИ пойти пакетной обработки.

В качестве альтернативы: используйте SNAPSHOT, чтобы запечатать "представление во времени" базы данных.

Другие вопросы по тегам