- •Глава 1. Базы данных и системы управления 9
- •Глава 2. Организация доступа к данным 45
- •Глава 3. Реляционная алгебра 60
- •Глава 4. Основы sql 67
- •Глава 5. Проектирование реляционных баз данных 89
- •Глава 6. Взаимодействие sql с приложениями 116
- •Глава 7. Некоторые проблемы администрирования баз данных 154
- •Базы данных и системы управления
- •Файловые системы
- •Концепция баз данных
- •Основные функции субд
- •Непосредственное управление данными во внешней памяти
- •Управление буферами оперативной памяти
- •Управление транзакциями
- •Журнализация
- •Поддержка языков баз данных
- •Трехуровневая модель архитектуры систем баз данных
- •Модели данных
- •Характеристика связей
- •Компьютерно-ориентированные модели данных
- •Реляционный подход
- •Ключи и целостность реляционных данных
- •Моделирование концептуальной схемы базы данных
- •Организация доступа к данным
- •Страницы и файлы
- •Индексирование
- •Структуры типа б-дерева
- •Хеширование
- •Методы сжатия
- •Метод дифференциального сжатия
- •Иерархические методы сжатия
- •Кодирование по методу Хаффмена
- •Реляционная алгебра
- •Традиционные реляционные операции
- •Специальные реляционные операции
- •Дополнительные реляционные операции
- •Примеры использования реляционной алгебры для выражения словесных запросов в виде формул
- •Основы sql
- •Типы данных
- •Строковые типы данных
- •Битовые типы данных
- •Точные числовые типы данных
- •Вещественные числовые типы данных
- •Календарные типы данных
- •Значения null
- •Создание и обслуживание таблиц
- •Запрос на выборку
- •Статистические функции
- •Создание соединений
- •Вложенные запросы
- •Запрос на объединение
- •Запросы, выполняющие реляционные операции вычитания, пересечения и деления
- •Запросы на изменение
- •Перекрестные запросы
- •Проектирование реляционных баз данных
- •Нормализация отношений
- •Функциональные зависимости
- •Н ормальные формы, обоснованные функциональными зависимостями
- •Нормальная форма Бойса–Кодда
- •Нормальные формы, обоснованные более сложными зависимостями
- •Процедура нормализации и проектирования
- •Пример проектирования базы данных
- •Назначение и предметная область
- •Проектирование базы данных
- •Взаимодействие sql с приложениями
- •Встраивание sql-операторов в программный код
- •Тип курсора
- •Триггеры
- •Хранимые процедуры
- •Стандартные интерфейсы для доступа к данным
- •Информационное окружение веб-сервера
- •Стандарт odbc
- •Уровни соответствия
- •Уровень соответствия odbc
- •Задание имени источника данных odbc
- •Расширяемый язык разметки xml
- •Xml как язык разметки
- •Материализация хмl-документов с помощью xslt
- •Создание хмl-документов на основе информации из базы данных
- •Некоторые проблемы администрирования баз данных
- •Оптимизация запросов
- •Параллельная обработка данных
- •Потеря обновления
- •Зависимость от незафиксированных обновлений
- •Несогласованный анализ
- •Блокировки транзакций
- •Согласованность и уровень изоляции транзакций
- •Распределенные системы баз данных
- •Фрагментация
- •Репликация
- •Распространение обновлений
- •Управление каталогом
- •Распределенная обработка запросов
- •Типы распределенных систем баз данных
- •Нераспределенные мультибазовые субд
- •Клиент-серверные системы
- •Системы с общими ресурсами
- •Технические аспекты администрирования базы данных
- •Восстановление базы данных
- •Безопасность баз данных
- •Шифрование данных
- •Производительность баз данных
- •Администрирование данных
- •Литература
Несогласованный анализ
Такая ситуация может возникнуть, когда одна транзакция получает доступ ко множеству записей в то время, когда некоторые из них обновляются другой транзакцией. Рассмотрим следующие две транзакции.
Т1: SELECT SUM(BALANCE) FROM ACCOUNTS;
Т2: UPDATE ACCOUNTS SET BALANCE = BALANCE – 100 WHERE ACCNO = 3; UPDATE ACCOUNTS SET BALANCE = BALANCE + 100 WHERE ACCNO = 1;
Вторая транзакция никак не должна повлиять на сумму балансов всех счетов, так как она просто переводит средства с одного счета на другой. Но посмотрим, что произойдет, если транзакции будут выполняться в такой последовательности (полагаем, что на четырех счетах лежит по 100 руб.):
Т1 извлекает счет 1. Баланс равен 100. Вычисляемая сумма 100.
Т2 извлекает счет 3. Баланс равен 100.
Т1 извлекает счет 2. Баланс равен 100. Вычисляемая сумма 200.
Т2 обновляет значение баланса счета 3. Оно становится равным 0.
Т1 извлекает счет 3. Баланс равен 0. Сумма 200.
Т2 извлекает счет 1. Баланс равен 100.
Т1 извлекает счет 4. Баланс 100. Сумма 300.
Т2 обновляет баланс счета 1, он становится равным 200.
Транзакция Т1 сообщит, что сумма балансов всех счетов равна 300, в то время как на самом деле она равна 400. Эта ситуация называется несогласованным анализом.
Блокировки транзакций
Чтобы избежать перечисленных выше проблем, в системах баз данных используются блокировки транзакций.
Когда транзакция получает доступ к определенному объекту базы данных, она должна заблокировать его. Другие транзакции не могут получать доступ к заблокированному объекту. Когда транзакция завершает обработку объекта, она снимает блокировку, что позволяет другой транзакции заблокировать и использовать данный объект.
Это означает, что когда две транзакции используют один и тот же объект, одной из них придется ожидать, пока транзакция, которая первой успела заблокировать объект, освободит его. Таким образом, могут создаваться "очереди блокировок" к объектам, которые используются множеством транзакций.
Блокировка может налагаться либо автоматически, по инициативе СУБД (неявная блокировка), либо по команде, которая передается СУБД прикладной программой или запросом пользователя (явная блокировка).
Блокировки могут быть неполными. Если две транзакции просто считывают одно и то же множество данных, не производя никаких обновлений, им не нужно блокировать данные друг от друга. Поэтому существует два типа блокировок: совместная (shared, S) и исключающая (exclusive, X) .
Если доступ к объекту осуществляется только для чтения, то на него налагается совместная S-блокировка. Исключающая X-блокировка налагается на объект, который подвергается изменениям (обновляется или удаляется). Таким образом, действует следующий протокол:
Если на объект наложен S-блок, на него можно налагать другие S-блоки. Транзакция, которой требуется Х-блок, должна ожидать, пока будут сняты все S-блоки.
Если на объект наложен Х-блок, никакие другие блоки на него налагать нельзя. Все транзакции, которым требуется блок (X или S), должны ожидать, пока этот Х-блок будет снят.
Данный протокол означает, что при выполнении операции, включающей только чтение (например SQL-оператор SELECT), по отношению к этому объекту могут параллельно выполняться и другие подобные операции. При выполнении операции обновления другие операции выполняться не могут. Этот протокол позволяет избежать перечисленных выше проблем параллельной обработки. Потеря обновления исключается, поскольку транзакция Т1 заблокирует счет 1234, прежде чем приступить к обновлению, и транзакция Т2 не сможет начать выполнение своих обновлений до тех пор, пока Т1 не закончит свои. Удается также избежать зависимости от незафиксированных значений, так как до тех пор, пока Т1 не завершит откат, она будет блокировать счет 1234 (т.е. Т2 не сможет получить к нему доступ). Что касается несогласованного анализа, Т1 наложит на все считываемые записи счетов S-блок. Таким образом, Х-блок, запрашиваемый Т2, не будет предоставлен ей до тех пор, пока Т1 не завершит свой анализ.
Бывают ситуации, когда в ходе выполнения отдельной транзакции требуются различные типы блокировки одного и того же объекта. Система должна внимательно следить за тем, когда можно снять ту или иную блокировку. Рассмотрим следующие запросы блокировок со стороны двух транзакций.
Т1: |
S-блок на объект 1 |
Т2: |
S-блок на объект 1 |
|
S-блок на объект 2 |
|
Х-блок на объект 1 |
|
Х-блок на объект 1 |
|
S-блок на объект 2 |
Обе транзакции собираются запросить Х-блок на объект 1. Если Т1 – логически первая транзакция, тогда важно гарантировать, что она получит этот блок раньше, чем Т2. Предположим, что блокировки снимаются сразу же после того, как закончена соответствующая обработка объекта. Тогда при одновременной работе транзакций возможна такая последовательность событий:
Т1 налагает S-блок на объект 1.
Т2 налагает S-блок на объект 1.
Т1 снимает S-блок с объекта 1 и налагает S-блок на объект 2.
Т2 налагает Х-блок на объект 1 (она может это сделать, поскольку Т1 сняла свою S-блокировку с данного объекта).
Т1 снимает S-блок с объекта 2. Теперь она должна ожидать предоставления Х-блока на объект 1.
Т2 снимает Х-блок с объекта 1 и налагает S-блок на объект 2.
Т1 налагает Х-блок на объект 1.
Т2 снимает S-блок с объекта 2.
Т1 снимает Х-блок с объекта 1.
В результате транзакция Т2 обновила объект 1 прежде, чем это сделала транзакция Т1. Такая последовательность действий ошибочна, поскольку Т1 – логически первая транзакция, т.е. ее результат должен быть зафиксирован в базе данных прежде, чем результат транзакции Т2. Рассматриваемое расписание событий противоречит принципу сериализации.
Принцип сериализации требует, чтобы при параллельном выполнении двух транзакций их результаты были такими же, как и в том случае, когда они выполняются строго последовательно, т.е. следующая транзакция не начинается до тех пор, пока предыдущая не завершится полностью. Таким образом, сериализация занимается рассмотрением конфликтующих запросов. В нашем примере конфликтующими запросами были запросы обеих транзакций на Х-блок объекта 1. График событий для определенного множества транзакций называется сериализуемым в случае, когда конфликтующие запросы в нем представлены в том же порядке, как если бы транзакции выполнялись последовательно. Другими словами, Х-блок на объект 1 должен запрашиваться транзакцией Т1 до того, как он запрашивается Т2.
Добиться сериализуемых графиков можно с помощью использования двухфазного протокола блокировки. Согласно данному протоколу, транзакция не может получить блок на некий объект после того, как она сняла с него блокировку.
В нашем сценарии Т1 не получит Х-блок на объект 1, если она к тому времени снимет S-блокировку с этого объекта, поэтому она ее не снимает. Следовательно, график событий будет таким.
Т1 налагает S-блок на объект 1.
Т2 налагает S-блок на объект 1.
Т1 налагает S-блок на объект 2.
Т2 запрашивает Х-блок на объект 1. Запрос отклоняется. Т2 ожидает.
Т1 налагает Х-блок на объект 1.
Т1 снимает все блоки.
Т2 налагает Х-блок на объект 1.
Т2 налагает S-блок на объект 2.
Т2 снимает все блоки.
Протокол называется двухфазным потому, что все транзакции проходят две фазы: фазу получения и фазу снятия блокировок. В большинстве систем вторая фаза откладывается до самого конца транзакции, когда транзакция готова выполнить фиксацию или откат, и блокировки снимаются только в этот момент (как и в рассмотренном примере), хотя такие действия не всегда обязательны. В нашем сценарии, например, Т1 может снять S-блок с объекта 2 перед тем, как наложить Х-блокировку на объект 1. Однако, откладывая снятие блокировок до окончания транзакции, система избегает необходимости анализировать будущие требования блокировок.