Краткая предыстория: моя прошлая заметка описывала подход к хранению и выборке данных, на котором можно построить конструктор приложений — альтернативу современным платформам разработки, но без необходимости программирования. Изобретение это потенциально может перевернуть весь мир IT, каким мы его знаем. Я провел патентный поиск и осветил результат публично, чтобы убедиться в отсутствии архитектурных аналогов. После чего получил патент и опубликовал статью с пояснениями, которая содержала несколько смелых замечаний насчет объемов, масштабируемости, быстродействия и прочего. Разумеется, статья вызвала большое количество вопросов, которые необходимо осветить отдельно: отличие от существующих решений и сравнительный анализ производительности и планов построения запросов к базе данных. А также ответить на вопрос: что это вообще такое и зачем?  Поскольку тема для многих больная, а заявленные преимущества весьма амбициозны, комментарии были достаточно резкими. Причина понятна — в статье все сразу видят «EAV», о которой серьезные люди до сих пор пишут исследования, при этом проблема производительности в общем случае не разрешима. Как мне любезно сообщили в комментариях, EAV имеет кучу недостатков, это общеизвестно, и любой, кто заявляет об окончательном решении проблем EAV, должен получить щедрых пинков в карму, дабы образумился. Самый популярный вопрос был: «чем это отличается от EAV, KV, Magento...». Казалось бы, отличия заключаются во всем что не укладывается в перечисленные свойства: Но такой ответ не устроил многих читателей, поэтому постараюсь объяснить более развернуто. Описанная структура использует справочник EAV, дополненный атрибутом ID, так как любой атрибут также является самостоятельной сущностью, могущей иметь свои атрибуты, равно как и использоваться в качестве справочного значения. То есть, структура предназначена не только как EAV-справочник, почему, собственно, я и не могу назвать это EAV. Чтобы объяснить, чем решение отличается от Datomic, Magento и десятков тысяч других решений и продуктов, понадобится десятки тысяч раз их сравнивать. Поэтому я рискну предложить простую методику, по которой за пару минут можно провести сравнение с любой системой и выявить разницу, если она есть. Нужно проверить выполнение следующих условий для сравниваемой системы: Если все обязательные условия выполнены, то перед вами система, попадающая под описание обсуждаемой здесь заметки. Для сравнительных тестов были сделаны две идентичные базы, одна из которых построена в обычных таблицах реляционной БД, а другая — с применением заявленной методики. Ниже приведены результаты тестов двух баз с текстами запросов, замерами времени и анализом планов выполнения. В комментариях к прошлой заметке была предложена простая структура связанных данных, пригодная для тестирования. Её я и взял за основу: это список из 1048552 книг 142654 авторов, сгенерированных из случайных данных. В конструкторе эта схема данных выглядит так:  Тестирование проводилось на самом простом сервере: 1 ядро @2.4GHz, 1GB RAM, диск SSD. Базы с индексами занимают 207 МБ в классической базе данных и 289 МБ в таблице конструктора. Для справедливости я буду делать серию запросов, поочередно в одной и другой базе, и замерять время. Первый предложенный оппонентом тест выглядел так: выбрать все книги, имя авторов которых содержит заданный текст. Для подобного запроса не может быть использован индекс по имени автора. Запрос к базе получился такой: Этот же запрос в конструкторе выглядит так (указан фильтр по автору и задано подсчитать их количество):  Имя автора содержит символы «aro», и под это условие попадает 465 книг в нашей базе. Запрос к таблицам вернул такой результат за 193 мс:  План выполнения запроса получился такой:  Конструктор вернул тот же набор за 266 мс:  Следует заметить, что за эти 266 мс конструктор выполнил 6 запросов к своей базе (проверил токен пользователя и его права, нашел мета-данные отчета, выполнил отчет). Собственно отчет выполнился за 264 мс. В базу был отправлен такой запрос: Такой был его план выполнения:  База, можно сказать, «холодная», поэтому время выполнения, должно быть, преувеличено. Выполним тот же запрос еще несколько раз, посмотрим что изменится, сведя все результаты в таблицу (время в секундах). Видно, что разница по времени примерно в полтора раза, при этом абсолютная разница во времени не может быть заметна на глаз. Оба решения работают достаточно быстро для комфортного восприятия в пользовательском интерфейсе. Поиск ограничен только той областью, где находятся данные нужного типа. Это обеспечивается описанными выше индексами и правилами выборки данных. В упомянутой Magento, например, то же самое достигается разнесением атрибутов по разным таблицам. Обычно поиск осуществляется с использованием индеска, например, по первым символам имени автора. Перепишем запрос следующим образом: В традиционной базе этот запрос выполнился за 3.1 мс:  В конструкторе все запросы для генерации страницы выполнились за 8.4 мс, из которых запрос отчета занял ровно 6 мс:  Выборка происходит несравнимо быстрее, потому что используются индексы, как мы и ожидали. В обычной базе данных:  В конструкторе:  Сделаем несколько аналогичных выборок наугад, занося результаты в таблицу (время в миллисекундах): По результатам в таблице можно сделать вывод, что чем больше записей возвращает запрос, тем больше конструктор проигрывает при сборе данных. При небольшом количестве записей конструктор начинает выигрывать, как это ни покажется странно. Применим фильтр к названию книги: поиск подстроки. Перепишем запрос так: Аналогичный запрос создадим в конструкторе:  Запустив эти два отчета увидим большую разницу во времени их выполнения: 148 мс в обычной базе и 2490 мс в конструкторе. Разница почти в 17 раз! К счастью, мы помним рекомендацию, данную в моей прошлой статье, которая велит нам переместить одну колонку отчета и начинать выборку с книги, а не с автора. Получится такой отчет:  Перезапустим оба отчета и опять увидим большую разницу во времени выполнения: 181 мс в обычной базе и 25 мс в конструкторе. Теперь, наоборот, конструктор отработал в 7 раз быстрее. Для чистоты эксперимента зададим порядок выборки в обычной БД: Еще раз выполнив оба отчета я получил такой тайминг: 62 мс в обычной базе и 47 мс в конструкторе. Вполне сравнимо. Похоже, обе базы на одном сервере как бы перетягивают одеяло на себя, и в замерах есть некоторые погрешности. В отличие от конструктора, оптимизатор обычной БД вряд ли перестроил план выполнения в последней редакции запроса. Логика организации данных такова, что конструктор будет исполнять запросы так же, без полного сканирования и с использованием индексов, при любом объеме данных. На действительно больших данных понадобится принимать аналогичные меры, как в традиционной БД. Напоследок сравним достаточно типичный случай: пользователь хочет найти книги определенного года и (или) с заданным количеством страниц. Вот наш запрос для этого: А так такой запрос выглядит в конструкторе:  Результаты различаются очень сильно, более чем в 30 раз в пользу конструктора:   Когда число таких запросов будет расти, производительность обычной базы без подстройки резко упадет, перечеркивая все её небольшие преимущества в проведенных тестах. Это загонит график в красную и бордовую зоны на картинке в начале статьи. Здесь мы плавно возвращаемся к вопросу, что это и зачем оно: это основа простого в освоении конструктора, позволяющего снизить риск лавинообразной деградации производительности. Конструктор дает более удобное средство работы с данными: сравните обычные запросы DDL и DML в этой статье с тем как это делается в конструкторе. Разработчик