Недавно мы протестировали подход, именуемый нами QDM, при работе с большими объемами данных — сотни гигабайт. В рамках задачи мы обрабатывали по 12-24 млн записей и сравнивали производительность квинтетного решения с аналогичным функционалом в обычных таблицах.
Мы не сделали каких-то новых открытий, но подтвердили те гипотезы, что озвучивали ранее: насколько всё таки универсальный конструктор в руках условного «чайника» проигрывает профессионально настроенной базе данных.
Также мы теперь знаем, что делать в подобной ситуации — решение достаточно простое и надежное, и имеем опыт организации компромиссного решения для сколько угодно больших данных.

В ходе разработки системы для сверки отчетности нам понадобилось загрузить данные одной из отчетных форм, в которой на каждую отчетную дату содержится до 24 млн записей. Данных там должно быть на 7 лет ежедневных расчетов. Объемы, прямо скажем, не для универсального конструктора, а для узкоспециализированной системы, но мы уже ввязались в эту затею и надо было искать решение.
Пользователи работают с этим большим массивом данных только в пределах одной отчетной даты, поэтому в эталонной системе всё это хранится в таблице, партиционированной по этой дате. Индексы по остальным 26 полям данных для этой формы не используются.
Первое, что мы сделали, разумеется — создали нужную структуру данных в конструкторе и загрузили туда несколько дат. Загрузка одной самой небольшой даты занимает около 14 часов, что уже неприемлемо долго: 12.5 млн записей по 27 атрибутов, положенные в полмиллиарда записей из 5 полей с построением трёх индексов, два из которых — составные.
Общий объем этих данных на диске чуть больше 18 ГБ.
Стоит заметить две особенности этой формы:
- Она почти не поддается нормализации, в отличие, например, от Формы 110, рассмотренной в предыдущей публикации
- В ней не используются индексы по атрибутам записей — пользователю выгоднее подождать минуту, чем тратиться на индексы
Это, можно сказать, самый радикальный случай, какой можно выбрать для сравнения. В большинстве случаев разница в объемах данных QDM и обычной базы не такая драматичная, а то и совсем мала.
Для сравнения, те же данные, загруженные в обычную таблицу реляционной базы данных, занимают 2.3 ГБ (в 8 раз меньше) вместе с индексом по дате, а их загрузка длится менее получаса (в 28 раз быстрее). В обоих случаях данные вставлялись напрямую из файла порциями по 100 тысяч записей, без отключе��ия индексов.
Памятуя, что для таких объемов данных использовать конструктор нецелесообразно, мы, тем не менее, сделали тесты производительности: для разных случаев сравнили массовую обработку записей конструктором и нашей неиндексированной таблицей. Нам нужно было определить границу объема данных, для хранения которых мы будем отныне использовать обычную таблицу, а не наш конструктор.
Как мы ожидали, работа с небольшими наборами данных, например, по отдельному счету или клиенту, в конструкторе выглядит достаточно комфортно (время отклика в пределах секунды), в отличие от таблицы без индексов, где отклика приходится ждать минутами. В то же время основная задача приложения — массовая выборка и агрегация данных в различных разрезах — может занимать в конструкторе в разы больше времени.
Ниже приведены сводные результаты выборок, которые мы делали для ступенчато возрастающего объема агрегируемых данных:
К-во записей | Время выборки, с | |
---|---|---|
Конструктор | Таблица без индексов | |
1 | 0.16 | 56 |
5 | 0.23 | 55 |
50 | 1.86 | 53 |
600 | 2.35 | 56 |
5000 | 14.7 | 56 |
12000 | 125 | 56 |
100000 | 254 | 57 |
650000 | 2663 | 57 |
1000000 | 2314 | 57 |
5000000 | 9675 | 69 |
12500000 | 764 | 89 |
Там, где это было возможно, мы делали несколько замеров, предварительно выбрав статистику и отбирая количество записей по маске номера счета.
Из таблицы и графика ниже видно, что агрегация полного набора данных внутри дня занимает заметно меньшее время, чем выборка свыше 5% данных с использованием индекса. Именно поэтому оптимизаторы запросов РСУБД игнорируют индекс в подобной ситуации, в то время как движок нашего сервиса на данных момент лишён такой возможности.
Графическое отображение тех же результатов с использованием логарифмической шкалы, чтобы сравнить числа разных порядков:

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

Теперь мы вынесем остальные подобные огромные таблицы, которых в нашей базе всего две дюжины из сотен, в отдельное хранилище, чтобы комфортно работать с ними.
Итак, мы можем использовать конструктор для небольших и средних таблиц, требующих интенсивного поиска и агрегацию по произвольным атрибутам, а большие неиндексированные объекты хранить в плоских традиционных таблицах, вызывать из стороннего хранилища или специализированных баз данных (Hadoop и прочих NoSQL).
Наилучшим образом конструктор подходит для CRM-систем и подобных продуктов, где пользователь работает с отдельно взятым клиентом, счетом или иной сущностью, а аналитические функции вынесены в отдельное специализированное хранилище.