Денормализация для увеличения производительности

Первый раз я столкнулся с намеренной денормализацией около года назад (на самом деле уже больше, статья давно в черновиках). В то время мы (Orange[UC]e) занимались оптимизацией скорости работы нашего JavaFX клиента. В одном из отчетов необходимо было осуществлять поиск по последним цифрам номеров телефонов. А в БД номера телефонов хранились в прямом виде. К моему большому сожалению, MariaDB (форк MySQL) не имеет возможности использовать индексы при поиске по концу строки (а номера у нас хранились в виде строк). Решение данной проблемы стало добавление столбца с перевернутым номером телефона, и добавлением индекса для этого столбца. Столбец с «прямым» номером решили тоже оставить, т.к. времени на переписывание логики на использование только перевернутого номера не было. Таким образом у нас получилось 2 столбца, которые содержат одни и те же данные.

Последний раз с денормализацией для увеличения производительности я столкнулся совсем недавно (около трех месяцев назад). Здесь все получилось намного интереснее. Подробности под катом.

Для начала опишем схему БД, с которой возникла проблема. Не знаю, могу ли я описывать реальную структуру, поэтому придумаем свою. Допустим у нас имеется 2 таблицы: main, minor. ER-модель схемы на рисунке ниже. В этих таблицах хранятся миллионы записей.

Исходная ER-модель
Исходная ER-модель

Для отчета нужны обе эти таблицы, заджойненные по main_id. Для фильтрации нужно использовать и main.timestamp и minor.phone_number (причем возможны ситуации когда нужно только что-то одно из двух). Пока в таблицах было менее миллиона строк — все было в порядке. Дальше отчеты строились все медленнее и медленнее. В какой то момент производительность упала ниже плинтуса. Эту проблему нужно было решать.

Решение было найдено достаточно быстро — денормализация. Мы просто добавили дублирующее поле timestamp в minor. И сделали составной индекс. Соответственно, теперь можно очень быстро выбирать только необходимые данные из таблицы minor и джойнить их с данными с таблицы main. А, когда нам необходимо получить только данные по timestamp — мы все еще можем использовать таблицу main.

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

П.С. Сам я не очень положительно отношусь к денормализации, но иногда без нее — никак.

Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.