Создание физической модели базы данных. Учет влияния транзакций
Денормализация методом слияния таблиц
Денормализация методом слияния таблиц - это процесс объединения одной или более нормализованных таблиц с целью устранения операций соединений или уменьшения в некоторых случаях числа операций вставки.
Возникает резонный вопрос: после того как мы вложили столько сил в нормализацию структур данных и разбивку сущностей, нам предлагается начать слияние таблиц? Фактически слияние оправдано в очень немногих случаях.
Один из примеров обоснованного применения слияния - наличие повторяющейся группы, которая гарантированно состоит из фиксированного числа элементов. Хорошими кандидатами на такое объединение являются таблицы со строкой для каждого месяца года или каждого дня недели. Единственный случай, где фиксированные группы надежны, - это когда они соответствуют абсолютно постоянным вещам, например дням недели.
Будет ли какое либо преимущество от такого слияния заранее сказать трудно. Подход к денормализации должен определяться требованиями к обработке данных.
Альтернатива данному способу денормализации - физическое размещение таблиц в кластере (например, как в СУБД Oracle). Это позволяет хранить рядом строки логически связанных отдельных таблиц.
Таким образом, на практике денормализация представляет собой набор приемов преобразования таблиц с целью повышения производительности обработки запросов. С точки зрения реляционной теории мы как бы не принимаем в рассмотрение наличие некоторых функциональных зависимостей в таблицах. Основным критерием проведения денормализации нормализованных таблиц являются требования к обработке данных. В реляционных базах данных следует избегать неоправданной денормализации таблиц.
Методы реализации денормализации: Разбиение таблиц базы данных
Разбиение (splitting) таблиц является одним из общих методов денормализации, который применяется в физическом проектировании реляционных баз данных. Разбиение таблиц бывает двух видов - вертикальное разбиение и горизонтальное разбиение.
Вертикальное разбиение является процессом перемещения некоторых колонок таблицы в другую новую таблицу, которая имеет тот же первичный ключ, что и исходная таблица. Горизонтальное разбиение является процессом перемещения некоторых строк одной таблицы в другую новую таблицу, которая имеет такую же внутреннюю структуру, что и исходная таблица.
Основные причины разбиения таблицы: либо существуют некоторые проблемы с производительностью запросов на этой таблице, либо непересекающиеся подмножества строк таблицы имеют значительное различие в производительности обработки. Т.е. подмножества строк таблицы редко встречаются в одном и том же запросе.
Вертикальное разбиение длинных строк
Проблемы с производительностью выполнения запросов на длинных строках таблицы являются наиболее частой причиной для выполнения вертикального разбиения таблицы. Критериями того, что строка является длинной, могут быть:
- длина строки больше, чем длина физической страницы базы данных (> 1 Кб);
- использование так называемого индекса хэширования (cluster hashed index).
Рассмотрим случай, когда длина строки больше размера физической страницы базы данных. Таблица в этом случае либо имеет слишком много колонок, либо некоторые колонки имеют большую длину. В этом случае СУБД при вставке строки в таблицу будет использовать одну или более дополнительных физических страниц для сохранения строки. Следовательно, при выборке строки из таблицы потребуется больше операций ввода/вывода на число дополнительных физических страниц. Производительность запроса при этом будет ухудшаться. Для увеличения производительности выборки можно разбить таблицу на одну или несколько таблиц с длиной строки подходящего размера.
Метод вертикального разбиения принципиально прост, если вспомнить, что разбиение эквивалентно реляционной операции проекции на таблице. Ясно, что некоторые колонки просто переносятся в новую таблицу так, чтобы длина оставшейся строки была подходящей (< 1 Кб). Разбиение не должно нарушать функциональных зависимостей между колонками. Поскольку мы предполагаем, что исходная таблица нормализована, в частности все неключевые колонки функционально полно зависят от первичного ключа, то первичный ключ новой таблицы является точной копией первичного ключа исходной таблицы.
Критичным вопросом является вопрос, какие колонки следует переносить в новую таблицу. При разбиении таблицы увеличение производительности будет достигаться только при раздельном доступе к полученным таблицам. При соединении полученных таблиц производительность такого запроса может быть ниже, чем с тем же запросом к исходной таблице из-за дополнительного ввода/вывода. Поэтому проектировщик данных, до того как принять решение о разбиении таблицы, должен проанализировать все транзакции к исходной таблице с высоким приоритетом и при разнесении колонок по таблицам руководствоваться принципом "частота совместного использования колонок в запросах, размещенных в каждой таблице разбиения, должна быть достаточно высока".
Пример. Обратимся к нашей учебной базе данных. Предположим, что в таблице EMPLOYEE необходимо дополнительно сохранять фотографию сотрудника и его автобиографию. Эти два новых поля имею достаточно большой размер, и длина строки таблицы заведомо превысит 1 Кб. Далее предположим, что существует 60 транзакций, которые обращаются к этой таблице. Только четыре из них обращаются ко всем колонкам: при вводе данных о сотруднике при приеме на работу, при внесении изменений, при удалении информации о сотруднике при его увольнении, и запрос руководителя, который имеет высокий приоритет. Все транзакции, кроме одной указанной выше, имеют средний и низкий приоритеты. Частота транзакции с высоким приоритетом ожидается не превышающей двух раз в неделю. Поэтому разбиение таблицы на две не сильно повлияет на производительность транзакций с высоким приоритетом в базе данных в целом.
Частота использования полей в транзакциях приведена в таблице 10.2.
Данная таблица не содержит частоты совместного использования колонок в транзакциях, но из частот использования полей в транзакциях можно сделать вывод о совместном использовании колонок. Вероятнее всего, колонки, имеющие близкие значения частот использования, используются и совместно.
Таким образом, проектировщик базы данных имеет основание для принятия решения о разбиении таблицы EMPLOYEE на две. Скажем, EMPLOYEE и EMP_ADD. Полученный фрагмент скрипта приведен ниже.
CREATE TABLE EMPLOYEE ( EMPNO integer NOT NULL, ENAME char(25), LNAME char(10), DEPNO int, SSECNO char(10), JOB char(25), SAL dec(9,2), COMM dec(9,2), FINE dec(9,2), PRIMARY KEY (EMPNO) ); CREATE TABLE EMP_ADD ( EMPNO integer NOT NULL, AGE date, HIREDATE date NOT NULL WITH DEFAULT, BIOG varchar(254), FOTO long varchar, PRIMARY KEY (EMPNO) );