Изоляция транзакций и чтение из нескольких таблиц в 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
Таблица.
У меня есть несколько вопросов:
Как правильно предотвратить изменение при чтении из нескольких таблиц одна за другой? Ни одна таблица не должна быть изменена, пока все не будут прочитаны.
Я использую SQL Server 2005 (в сети) и SQL Server 2005 Express (локальный). Можно ли явно получить блокировки для нескольких таблиц одновременно?
Если я запускаю свою локальную базу данных 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 он работает нормально, но это может быть из-за медленного соединения и, следовательно, более низкой вероятности одновременного выполнения.
На моей локальной базе данных я начинаю каждую транзакцию с фиктивной
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, чтобы запечатать "представление во времени" базы данных.