Изоляция транзакций и чтение из нескольких таблиц в SQL Server Express и SQL Server 2005 - PullRequest
3 голосов
/ 09 декабря 2011

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

Например:

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

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

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

Я установил

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
    

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

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

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

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

Ответы [ 2 ]

3 голосов
/ 09 декабря 2011

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

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

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

0 голосов
/ 09 декабря 2011

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

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

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

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

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

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

...