Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Тарасов С. В. СУБД для программиста. Базы данных изнутри

.pdf
Скачиваний:
80
Добавлен:
29.11.2021
Размер:
4.08 Mб
Скачать

средств, но в отчётности нет-нет да и проскакивали непонятные значения типа «Оглы П.Б.Б.».

Следует отметить, что при добавлении к этому учёту клиентовиностранцев, проектировщиков логической схемы БД не спасла бы и более структурированная форма из трёх колонок для раздельного хранения фамилий, имён и отчеств. Потому что это проблема уровня концептуального проектирования и соответствующих моделей: необходим синтез не привязанной к модели данных структуры, способной вмещать в себя комбинации имён людей разных стран и культур.

2НФ

Вторая нормальная форма (2НФ) означает, что выполнены требования 1НФ, при этом все атрибуты целиком зависят от составного ключа и не зависят ни от какой его части.

Напервыйвзглядкажется, чтонарушения2НФпрактическиневозможны, потому что чаще всего в качестве первичных ключей используются автоинкрементные целочисленные значения или иные суррогаты для реализации ссылок. Однако, в определении говорится о ключах вообще, а не только о первичных. В отношении может быть несколько ключей, и некоторые из них могут являться составными. Такие ключи следует подвергнуть проверке в первую очередь.

Ассоциативная таблица — таблица, имеющая ключевые связи с двумя и более таблицами

Например, если каждая операция сбыта мебельной продукции в таблице продаж однозначно характеризуется колонками идентификатора товарной позиции, даты продажи и идентификатором покупателя, то нахождение в той же таблице столбца «Тип материала», зависящего непосредственно от товарной позиции, должно немедленно привлечь ваше внимание.

Аномалия в данном случае приведёт только к избыточности хранения в виде размера идентификатора, помноженного на число строк таблицы (без учёта индексов). Но если в той же таблице обнаружится ещё и колонка

91

«Контактный телефон», присущая атрибутике покупателя, то последствия окажутся более серьёзными. Кроме избыточности хранения при ошибке ввода придётся исправлять номер телефона во всех записях о продажах данному покупателю.

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

3НФ

Третья нормальная форма (3НФ) означает, что выполнены требования 2НФ, при этом в между атрибутами отношения нет транзитивных зависимостей.

Что такое транзитивная зависимость легко понять на примере уже упоминавшейся выше таблицы продаж — типичного примера ассоциативной таблицы.

Предположим, что продажа каждой товарной позиции имеет своим основанием документ (заказ, счёт и т.д.), а её стоимость характеризуется ценой, количеством и валютой. В этом случае имеем следующие зависимости между атрибутами (колонками):

«Идентификатор продажи» → «Номер документа»

«Идентификатор продажи» → «Код валюты»

«Номер документа» → «Код валюты»

Эти зависимости транзитивны: каждая продажа однозначно определяет свой документ-основание и расчётную валюту, однако, валюта определяется ещё и документом.

Результатом нарушения 3НФ является избыточность хранения и необходимость обновления данных в связанной таблице. Так, если вы оставите колонку «Код валюты» в таблице продаж, то при изменении

92

валюты документа придётся также обновлять все связанные с ним строки продаж.

Деморализуем... то есть денормализуем: «звезда» и «снежинка»

Как можно понять из вышеприведённых примеров, основными целями нормализации являются:

устранение избыточности при хранении данных, приводящей к увеличению размера БД;

исключение необходимости модификации данных в связных таблицах для минимизации времени и операций, проводящихся в одной транзакции. Или, как выражаются специалисты, уменьшить толщину транзакции, потому что толстые транзакции мешают при многопользовательской работе взаимными блокировками и увеличением времени отклика системы. Речь об этом пойдёт в отдельной главе.

Но список заявленных целей касается приложений транзакционных.

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

Зачем это нужно?

Наиболее дорогостоящая с точки зрения вычислительных ресурсов операция между большими таблицами — соединение. Соответственно, если в одном запросе необходимо «провентилировать» несколько таблиц, состоящих из многих миллионов строк, то СУБД потратит достаточно много времени на такую обработку. Пользователь в это время может отойти выпить кофе. Интерактивность обработки практически исчезает и приближается к таковой для обработки пакетной. Даже хуже, в пакетном режиме пользователь с утра получает все запрошенные накануне данные и спокойно работает с ними, подготавливая новые запросы к вечеру.

Чтобы избежать ситуации тяжёлых соединений таблицы денормализуют. Но не абы как. Существуют некоторые правила, позволяющие считать

93

денормализованные с точки зрения транзакционной обработки таблицы «нормализованными» согласно правилам построения таблиц для хранилищ данных.

Основных схем, считающихся «нормальными» в аналитической обработке, две: «снежинка» и «звезда». Названия хорошо отражают суть и следуют непосредственно из картинки связанных таблиц.

В обоих случаях центральным элементом схемы являются так называемые таблицы фактов, содержащие интересующие аналитика события, транзакции, документы и другие занятные вещи. Но если в транзакционной БД один документ «размазан» по нескольким таблицам (как минимум по двум: заголовки и строки-содержание), то в таблице фактов одному документу, точнее, каждой его строке или набору сгруппированных строк, соответствует одна запись. Сделать это можно денормализацией двух вышеупомянутых таблиц.

Рис. 19. Денормализация документов в таблицу фактов

94

Теперь можно оценить, насколько облегчится для выполнения СУБД запрос, например, следующего вида: определить объёмы продаж муки клиентам «ООО Пирожки» и «ЗАО Ватрушки» за период.

В нормализованной транзакционной БД

SELECT

SUM(dl.qty) AS total_qty, SUM(dl.price) AS total_amount, c.name

FROM docs d

INNER JOIN doc_lines dl ON d.id_doc = dl.id_doc

INNER JOIN customers c ON d.id_customer = c.id_customer INNER JOIN products p ON dl.id_product = p.id_product

WHERE

c.name IN ('ООО Пирожки', 'ЗАО Ватрушки') AND p.name = 'Мука' AND

d.date BETWEEN '2014-01-01' AND '2014-02-01' GROUP BY c.name

В аналитической БД

SELECT

SUM(s.qty) AS total_qty, SUM(s.amount) AS total_amount, c.name

FROM sales s

INNER JOIN customers c ON d.id_customer = c.id_customer INNER JOIN products p ON dl.id_product = p.id_product

WHERE

c.name IN ('ООО Пирожки', 'ЗАО Ватрушки') AND p.name = 'Мука' AND

s.date BETWEEN '2014-01-01' AND '2014-02-01' GROUP BY c.name

Вместо тяжёлого соединения между двумя таблицами документов и их состава с миллионами строк, СУБД достаётся прямая работа с таблицей фактов и лёгкие соединения с небольшими вспомогательными таблицами, без которых также можно обойтись, зная идентификаторы.

SELECT

SUM(s.qty) AS total_qty, SUM(s.amount) AS total_amount, s.id_customer

FROM sales s

WHERE

95

s.id_customer IN (1025, 20897) AND s.id_product = 67294 AND

s.date BETWEEN '2014-01-01' AND '2014-02-01' GROUP BY s.id_customer

Вернёмся к схемам «звезда» и «снежинка». За кадром первого рисунка остались таблицы клиентов, их групп, магазинов, продавцов и, собственно, товаров. При денормализации эти таблицы, называющиеся измерениями, также соединяются с таблицей фактов. Если таблица фактов ссылается на таблицы-измерения, имеющие ссылки на другие измерения (измерения второго уровня и выше), то такая схема называется «снежинка».

Рис. 20. Таблица фактов в схеме «снежинка»

Как можно заметить, для запросов, включающих фильтрацию по группам клиентов, приходится делать дополнительное соединение.

SELECT sum(amount) FROM sales s

INNER JOIN customers c ON s.id_customer = c.id_customer WHERE c.id_customer_group IN (1, 2, 10, 55)

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

96

Схема, в которой таблица фактов ссылается только на измерения, не имеющие второго уровня, называется «звезда». Число таблиц измерений соответствует числу «лучей» в звезде.

Схема «Звезда» полностью исключает иерархию измерений и необходимость соединения соответствующих таблиц в одном запросе.

SELECT sum(amount) FROM sales s

WHERE s.id_customer_group IN (1, 2, 10, 55)

Рис. 21. Таблица фактов в схеме «звезда»

Обратной стороной денормализации всегда является избыточность, являющаяся причиной увеличения размера БД как в случае транзакционных, так и аналитических приложений. Давайте посчитаем примерную дельту на приведённом выше примере преобразования «снежинки» в «звезду».

Положим, таблица продаж не использует компрессию данных и содержит около 500 миллионов строк, а количество групп покупателей порядка 1000. В этом случае мы можем использовать в качестве типа идентификатора id_customer_group короткое целое (shortint, smallint), занимающее 2 байта.

97

В некоторых СУБД, например Oracle, специальные целочисленные типы на уровне определений схемы БД отсутствуют, необходимо использовать универсальный логический тип numeric(N), где N — число хранимых разрядов. Размер хранения такого числа рассчитывается по специальной формуле, приводимой в документации по физическому хранению данных, и, какправило, онпревышаеттаковойдлянизкоуровневыхтиповвроде«16битное целое» на 1-3 байта.

Будем считать, что наша СУБД поддерживает двухбайтовый целочисленный тип (например, PostgreSQL, SQL Server, Sybase и другие). Тогдадобавлениесоответствующейколонкиid_customer_groupвтаблицу продаж вызовет увеличение её размера как минимум на

500 000 000 * 2 = 1 000 000 000 байт ≈ 1 гигабайт.

Универсальных рекомендаций по денормализации не существует, это всегда компромисс между размером БД и временем выполнения запросов. Если вы исчерпали все возможные способы оптимизации запросов и физического хранения на данной схеме БД, то следует рассмотреть возможность её дальнейшей денормализации, что, однако, не является единственным путём решения проблем производительности системы. Более распространённый способ — организация на основе хранилища данных ещё более агрегированных таблиц (витрин) и многомерных кубов, которые и будут непосредственно служить базами данных для запросов пользователей.

Типовая архитектура данных аналитических приложений

Особенность аналитической обработки — тяжёлые запросы по произвольным критериям выборки. Сколь ни старались бы вы оптимизировать хранилище данных, всегда найдутся запросы, выполняющиеся медленнее, чем требуется.

Поэтомупроектировщикианалитическихсистемпришликидееразделения собственно хранилища (data warehouse), где данные представлены в минимально агрегированном виде, и конечных БД, адаптированных под нуждыпользователейразных профилей и предметных областей.

98

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

Витрина данных представляет собой реляционную БД или даже одну таблицу фактов, содержащую более агрегированную и отфильтрованную информацию, извлечённую непосредственно из хранилища данных.

Рис. 22. Логическая архитектура аналитических приложений

Например, реальная схема «звезда» из предыдущей главы должна содержать десятки измерений, в том числе определяющие географию продаж и классификацию товаров. В этом случае имеет смысл извлекать информацию по конкретным регионам и типам товаров, помещая её в витрины данных пользователей соответствующих подразделений. Торговые представители в данной стране не нуждаются в информации о продажах на материках другой стороны глобуса. Агрегированная и отфильтрованная таблица продаж соответствующей витрины может содержать на порядки меньше записей, чем исходная таблица хранилища.

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

99

расходы на разработку и поддержание в актуальном состоянии многочисленныхпакетовETL17 дляпереносаданныхизоднойБДвдругую.

Как и в случае денормализации таблиц, декомпозиция единой БД хранилища на многочисленные витрины и кубы — предмет компромисса между требуемой производительностью и накладными расходами на содержание более сложной децентрализованной инфраструктуры.

Переносимость между СУБД

Сюжет переносимости приложений между разными СУБД является с технологической точки зрения в большей степени предметом программирования, нежели проектирования. Тем не менее, о некоторых проблемах следует подумать гораздо раньше, чем будут написаны первые строки кода и отлажены первые запросы.

Есть достаточно распространённое мнение, источником которого являются прежде всего, специалисты по эксплуатации конкретных СУБД, знающие цену интеграции, тонкой настройки и оптимизации физического уровня. Суть мнения состоит в следующем высказывании: «Невозможно разработать приложение, эффективно работающее с разными СУБД».

Не привязываясь к размытости термина «эффективно», следует признать, что это вполне логичная интерпретация другого известного в системной инженерии факта «универсальная система менее эффективна, чем специализированная». Да, универсальная ЭВМ может быть гораздо менее производительна, чем специализированная. Однако, мы все в большинстве своём работаем на универсальных персональных ЭВМ, а не на спецвычислителях, имеющих свои области применения.

Сдругой стороны, вы уже знаете, что миры реляционной модели данных

ипромышленных РСУБД хоть и пересекаются, но далеко не на 100 %. Таким образом, задача переносимости имеет место, и решать её надо, даже

17От англ. Extract-Transform-Load (ETL), программа для извлечения, преобразования и загрузки данных между их источником и приёмником. Программа обычно работает в пакетном режиме, поэтому ETL часто называются пакетами.

100