В прошлой лекции мы убедились, что нормализация (декомпозиция отношений) увеличивает целостность, но понижает производительность
На этой лекции посмотри на два подхода, позволяющие увеличить производительность
Один из таких подходов - использование индекса
В случае с хранением в оперативной памяти, где доступ очень быстрый, в диске доступ очень медленный, неговоря о возможной фрагментации диска
Поэтому, чтобы найти условного студента в файле при помощи условного двоичного поиска, нужно а) содержать файл сортированным, что дорого, и б) т. к. файлы на диске расположены блочно, то приходится прочитывать весь блок, что увеличивает время работы
А давайте придумаем некий индекс, который представим в виде двоичного дерева, в котором хранятся первичный ключ и адрес на место в диске. Помимо этого такой индекс мы можем размещать на оперативной памяти
Тут же можем выделить 3 типа индекса:
Первичный индекс - индекс, созданный по первичному ключу отношения, которое упорядочено по первичному ключу
И с первичным индексом можем найти недостаток: хранение отсортированного порядка отношения (дорого, но обеспечиваем дешевый джоин); и преимущество: скорость поиска
Индекс кластеризации - индекс, созданный по неключевому полю отношения, которое упорядочено по этому полю
Заметим, что индекс получается неплотным - он не указывает на каждый кортеж. Из-за этого отношение группируется в кластеры по значению избранного поля.
Вторичный индекс - индекс, построенный по полю не упорядоченного по нему отношения
Из определения очевидно, что поле должно быть уникальным ключом - отношение не упорядочено, значит, кластеров не будет.
Заметим, что при этом два индекса сразу мы не можем создать для одной таблицы - и на этом концепция индекса заканчивается
Индекс также различают по плотности на:
Плотный индекс - индекс, в котором одному узлу соответствует одна запись
Разреженный индекс - индекс, в которому одному узлу соответствуют несколько записей
А если мы начнем делать индекс для атрибута-строки, то мы неизбежно придем к хеш-фукнциям, и тут тоже есть свои нюансы, например, для электронных почтовых адресов используют хеш от реверса строки, чтобы не допускать естественную кластеризацию
Второй же подход - это представления
Допустим такую модель:
“Студент”
ИСУ | ФИО | N группы | Форма обучения |
---|---|---|---|
“Группа”
N группы | ОП |
---|---|
“Образовательная программа”
ОП | Факультет |
---|---|
“Паспорт”
ИСУ | Паспорт |
---|---|
Индексы в этом ситуации будут бесполезны
Появляется идея: что, если вместе с нормализованной моделью хранить и денормализованную:
ИСУ | ФИО | N группы | Форма обучения | ОП | Факультет |
---|---|---|---|---|---|
Тут приходим к:
Представление - динамически сформированный результат одной или нескольких реляционных операций, выполненных с целью получения нового отношения
Представления делятся на материализованные и представления заменой
Материализованное представление хранится в памяти. В этом случае надо создавать некий таймер или триггер на пересоздание представления, НО:
По сути материализованное представление - это банальный кеш. И тут возникает проблема неактуальности кеша: допустим ситуацию, что база данных актуализируется ночью; студент в день комиссии утром подписывает заявление об академическом отпуске, а вечером комиссия, которая не знает о его уходе, отчисляет его🦆
Представление заменой хранится в виде запроса, на который в нужное время заменяется таблица, доступ к котором мы хотим получить.
Но, как мы знаем, дополнительные абстракции приводят к ухудшению производительности, но зато мы выигрываем в безопасности: мы можем отдать это представление другой конторе и выдать доступ к только нужным по нашему мнению полям
Представления могут быть обновляемыми и необновляемыми, но не все представления могут быть обновляемыми из-за race-condition. Хороший пример на эту тему - воскрешение студента: студент подал заявление на перевод между группами в июле, но эта транзакция перевода должна выполниться в сентябре, на комиссии его отчислили, но транзакция по переводу групп выполнилась после отчисления, и, таким образом, его зачислили обратно🦆
Но тем не менее также усложняется запись данных через представление - нам нужно знать его структуру
Здесь выделим преимущества представления:
Повышение защищенности данных - как в примерах выше
Снижение сложности доступа к данным - инженеры баз данных хранят эти сокральные знания об этой модели, и всем остальным разработчикам не надо спрашивать об этом их
И недостатки представления:
Ограниченные возможности обновления
Структурные ограничения - представления вводят ограничения на рефакторинг базы данных
Снижение производительности
И по большей части это все костыли, которые сломали невыполнимую идею Кодда. Но тем не менее все эти недостатки и преимущства - баланс, в котором мы ищем решение