Pull to refresh

Comments 193

Стесняюсь спросить, так чего в итоге изобрели-то? (Следующий вопрос будет — зачем?)
Человек заново «изобрел» adjacency list model (очевидно не подозревая о ее существовании) прикрутив к ней зачем то еще дополнительное поле типа. Более того он утверждает, что
не используются триггеры и constraints, просто потому что всё это до сих пор не понадобилось
при этом не объясняя как ему удается сохранять консистентность хранимых данных и не терять ресурсы и производительность на рекурсивных запросах.
Я думаю это просто следствие того, что он не знает про limitations of the adjacency list model.

UltimaSol пожалуйста, прежде чем патентовать что-то — прочтите для общего развития хотя бы вот эту простую статью из топа гуглопоиска по данной теме.
Если не можете читать на английском — хабр вам в помощь.
Вон например люди еще в 2012 году в статье и обсуждении размышляли как можно улучшить Adjacency List (что-то вроде ваших типов в отдельной таблице), но им даже в голову не пришло патентовать очевидные вещи!
прикрутив к ней зачем то еще дополнительное поле типа

Как вы можете рассуждать, не понимая о чем речь?
По одной из ссылок вообще информация из одного из ближайших патентов 1994 года, вы это знали?
Только там кусок решения для частного случая, у меня же — целое, законченное решение.
Как вы можете рассуждать, не понимая о чем речь?
Ок, не хочу больше спорить про техническую сторону.
Последний вопрос к UltimaSol:
Правильно ли я понимаю что вы запатентовали структуру данных?
Неправильно.
Систему хранения и способ обработки.

А ознакомиться с патентом где-нибудь можно?

Я же дал здесь ссылку. Вы просто пишете, не читая. Пишите дальше.

Ссылку на патент? В посте я ее не нашел. Вас не затруднит повторить, я надеюсь.

То есть если кто-то сделает аналогичную структуру, только будет хранить значения типов по разным таблицам (отдельно целые числа, отдельно строки, ...), это будет другая система, и он не нарушит патент?

А если кто-то уже сделал структуру данных с аналогичными столбцами, только в разных таблицах, или с дополнительными столбцами, это другая система или ваш патент недействительный?
С точки зрения патентного права, оба случая закрыты этим патентом.
Хотя это всё вообще не важно.
В таком случае, с точки зрения патентного права ваш патент недействительный. Так как подобные структуры базы данных существовали и до него.

Magento EAV


Обратите внимание на названия полей.

Я правда не разбираюсь в патентах, но в обратном случае в существовании патентов не было бы смысла.
Обратите внимание на названия полей.

Я правда не разбираюсь в патентах, но в обратном случае в существовании патентов не было бы смысла.


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

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

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

… в частности, понимая под функционально эквивалентной следующую структуру таблицы catalog_product_entity_attribute:


  • entity_id
  • `attribute_id
  • value_int
  • value_decimal
  • value_char
  • value_lob
  • value_entity_id
  • далее аналогично

(BTW, если я правильно вкурил статью по ссылке, у мадженты в ее ...entity_attribute... тоже ведь есть entity_id, странно, что его на схеме нет)

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

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

Структуру данных запатентовать нельзя, во всяком случае в РФ.
Это я к тому, что вы не разобрались в сути статьи.
Систему хранения и способ обработки.

В таком случае что подразумевается под словами "система хранения"?

Система — это не только структура.
Даже структуру многие комментаторы здесь трактуют неверно, редуцированно. Систему же в целом они совсем отказываются понимать.
Похоже вы не понимаете. Вы сделали патент, который теоретически может причинить другим людям трудности в работе. Потрудитесь пожалуйста объяснить, что именно вы патентовали, и в чем отличие вашей системы от EAV, EAV/CR и их реализаций.
Осмелюсь заявить, что это вы не понимаете.
Чем отличается от EAV, EAV/CR, KV и иже с ними, я уже отчаялся объяснить.
Давайте так сформулирую: ни одно существующее ныне решение не будет ущемлено этим патентом. Просто потому что они с ним не конфликтуют.
Годится?
Чем отличается от EAV, EAV/CR, KV и иже с ними, я уже отчаялся объяснить.

А вы пытались?

Все еще нет.


Правильно ли я понимаю, что единственным значимым отличием вашего решения от "типового" EAV является добавленная колонка ID, по которой построен первичный ключ и кластерный индекс (изменения в остальных индексах — следствие этого кластерного)?

Некорректный вопрос, типа: «Чем отличается канал от канализации».
Что такое EAV?
Что такое Система хранения данных и способ выборки?
Ответьте на эти два вопроса в ваших терминах и увидите разницу.
Не будет разницы в ваших терминах — считайте, что это одно и то же. Будет — тем лучше.
И в любом случае получите ответ на свой вопрос.
Что такое EAV?
Что такое Система хранения данных и способ выборки?

EAV — это, в числе прочего, способ хранения данных, и, как следствие, способ выборки.


Очевидно, что это не "одно и то же" (не всякий способ хранения — EAV), но одно есть частный случай другого (EAV — это один из способов хранения данных).


И в любом случае получите ответ на свой вопрос.

Так и не получил.

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

Вот именно поэтому вам и говорят, что вы не потрудились объяснить различия. Вы везде описываете свою систему, но когда вам задают конкретные вопросы о различиях — вы от них уходите.

Нет. Потому что факты противоречат вашим словам. Начиная с "Это не EAV, поэтому подразумеваемых вами недостатков тут нет", заканчивая "Вы приводите часть некоей структуры, которую никак нельзя трансформировать в мою обратимыми преобразованиями (перестановка полей, транспонирование таблиц, декомпозиция и объединение и т.д.)".


я уже отчаялся объяснить

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


Я повторяю свою просьбу. Напишите отдельным комментарием список основных отличий вашего решения от EAV как подхода к хранению и его реализации на примере допустим Magento. В виде "В EAV делается так, у меня так, отличие в этом. В Magento реализовано так, у меня так, отличие в этом". Тогда будет понятно, не нарушает ли кто-то ваш патент, и не нарушаете ли вы чьи-то патенты.

Я повторяю свою просьбу. Напишите отдельным комментарием список основных отличий вашего решения от EAV как подхода к хранению и его реализации на примере допустим Magento.

Вот что написано в статье:
Все данные физически хранятся в одной таблице из 5 полей: ID, родитель (ID), тип (тоже ID), порядок среди равных (число), значение (набор байтов). У неё есть 3 индекса: ID, тип-значение, родитель-тип. Вместо обращения к базе данных, которая найдет таблицу, в ней найдет поле, в котором найдет данные, ядро обращается к единственной таблице, в которой по индексу сразу находит данные нужного типа.

Идем в Маженту, ищем там таблицу с такими полями и такими индексами. Ну вот, скажем, индекс тип-значение есть хоть где-то?

А более эффективные индексы считаются? Или обязательно надо, чтобы было точно как у вас?

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

Вы хотите сказать, что с точки зрения патента индекс Type, Value эквивалентен индексу Type, Value, Parent? Какое у вас удобное патентное право.

Ну вот, скажем, индекс тип-значение есть хоть где-то?

В Datomics есть.

Вы приводите часть некоей структуры, которую никак нельзя трансформировать в мою обратимыми преобразованиями (перестановка полей, транспонирование таблиц, декомпозиция и объединение и т.д.).
Еще раз, выше я писал, что парой-тройкой джоинов можно трансформировать практически любое EAV хранилище к вашей структуре.
Вот для примера код для Magento:
SELECT
`product`.`entity_id` AS `ID`,
`parent_id` AS `Parent ID`,
`entity_int`.`attribute_id` AS `Type ID`,
`sort_order` AS `Order`,
`value` AS `Value`
FROM
catalog_product_entity AS `product`
JOIN catalog_product_relation AS `relation`
ON product.entity_id = relation.child_id
JOIN catalog_product_entity_int AS `entity_int`
ON product.entity_id = entity_int.entity_id
JOIN eav_entity_attribute as `attribute`
ON entity_int.attribute_id = attribute.attribute_id
Он выбирает `ID`всех простых товаров, которые входят по `Parent ID` в составные товары, для каждого `ID` выбирается тип целочисленного атрибута `Type ID` отсортированный по порядку аттрибутов `Order` со значением `Value`, на выходе получаем что-то вроде такого:

Чем эта таблица отличается от вашей?
Это не таблица, это выборка из таблиц.
Трансформация структуры — это когда вы переставляете столбцы, денормализуете или нормализуете таблицы, объединяете поля данных или разделяете их. При этом не происходит потери данных, а сама конечная структура содержит всю информацию для однозначного обратного преобразования.

Но это не главное.
Вам следует уяснить, что набор полей — это только набор полей, и он не может быть защищен авторским правом или патентом.
Т.е. если кому-то понадобится использовать в своем ПО таблицу аналогичную вашей
из 5 полей: ID, родитель (ID), тип (тоже ID), порядок среди равных (число), значение (набор байтов)
и все, автоматически вытекающие из этой структуры варианты запросов к этой таблице — он не нарушит ваш патент?
Ели нет — то зачем тогда это нужно было патентовать?
Ели нет — то зачем тогда это нужно было патентовать?

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

Если бы только это. Самое мерзкое, что потом патентные тролли выкупают такие патенты и «тошнят» ими всех, до кого могут дотянуться!
Патентом защищена система: структура из 4 полей (Order — необязательное поле) с этими индексами и принцип выборки из этой единой таблицы.

Если, например, кто-то сделает отдельные таблицы под разные типы (и размерность) данных, чтобы работал индексируемый поиск по диапазонам чисел, и будет делать JOIN разных таблиц, в зависимости от базового типа данных, то это будет в рамках этого патента.

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

Убираете из таблицы любое из обязательных 4 полей или индекс — всё, это уже не изобретение, о котором мы тут рассуждаем.

Так, давайте все-таки разберемся с маджентой.


структура из 4 полей

Есть (value_id, entity_id, attribute_id, value). Остальные поля попадают под ваше "если добавить поля в эту таблицу[...], то это также нарушение патентного права". Разные таблицы попадают под "если, например, кто-то сделает отдельные таблицы под разные типы [...] данных".


Остаются индексы.


  • первичный ключ по value_id: есть
  • кластерный ключ по value_id: насколько я понимаю, MySQL делает это автоматически для первичного ключа, то есть тоже есть
  • индекс entity_id, attribute_id: есть

Нет только индекса attribute_id, value_id, но есть индекс attribute_id.


И вот теперь у меня вопрос: если DBA, наблюдающий за БД с маджентой, решит добавить индекс attribute_id, value_id, кто конкретно нарушит патентное право — маджента или DBA? А если это сделает автооптимизатор в MS Azure (я знаю, что для этого нужно еще пару условий выполнить, но не суть)?

Слишком много «если».
Описанный здесь подход нигде не используется в точно таком виде.
Если вдруг начнет использоваться после появления этой статьи, то тогда будет что обсудить.
Слишком много «если».

Ровно одно. И это очень простой случай: администратор посмотрел на логи работы мадженты и решил добавить индекс. Нарушен ваш патент или нет?

Я так сразу не могу ответить, опыта нет.
Надо пробовать.

Пробовать что, простите? Добавить индекс и подать иск?

Для начала добавить индекс и посмотреть, что будет.
Потом можете подать иск (не знаю, к кому и на что, ибо это не моя идея, а ваша).

Для начала добавить индекс и посмотреть, что будет.

А какая разница? Речь-то идет о том, какие существующие реализации конфликтуют с вашим патентом, а какие — нет.


Меня, пожалуй, тоже начинает интересовать заданный выше вопрос: а зачем вы патентовали свое решение?

Описанный здесь подход нигде не используется в точно таком виде.

Кстати, а как вы вообще можете это утверждать?

Патентом защищена система: структура из 4 полей
Это самая тривиальная структура! Достаточно погуглить по create table parent_id type_id value и вы найдете кучу решений использующих этот подход задолго до вас! Он настолько очевиден, что люди используют такие же имена полей — вот парочка ссылок с первой же страницы поиска:
2013 CREATE TABLE myproducts (uid, parent_id, type_id, name ...
2007 CREATE TABLE menu_menuitem (id, parent_id, type_id, order, title
Это не таблица, это выборка из таблиц.
Трансформация структуры — это когда… конечная структура содержит всю информацию для однозначного обратного преобразования.
Если мне заплатят, то я могу все таблицы Magento с их данными свести к одному Adjacency List, который будет содержать всю информацию для
однозначного обратного преобразования
Точно также как и привести ее к вашей структуре (которая является разновидностью Adjacency List) с возможностью обратной трансформации. Означает ли это, что Magento нарушает ваш патент?
Если мне заплатят, то я могу все таблицы Magento с их данными свести к одному Adjacency List, который будет содержать всю информацию для

Собственно, я примерно так и сделал, сам себе заплатив. А затем добился работоспособности всего этого, создав индексы и алгоритм выборки.
Получилась система, отличная от Magento, и никто ничего не нарушает в данном случае.

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


Другое дело, что если кто-то на основании этого патента попробует опротестовать новосозданные EAV, немедленно случится встречный иск на более раннее изобретение.


Вообще, конечно, этот патент — это прекрасная иллюстрация к тезису "запатентовать можно что угодно". Особенно жгут "фиг. 8" и следующее к ней обоснование:


Основная проблема информационных систем — это растущая цена их поддержки при возрастании сложности системы, причем зачастую затраты на разработку и сопровождение растут экспоненциально (см. Фиг. 8). Два основных фактора риска здесь: несовершенство разработки программного кода и компромисс при выборе архитектуры базы данных. Заявляемая система позволяет пользователю самостоятельно задать сколько угодно сложную структуру данных и правила их обработки без необходимости создания таблиц базы данных, индексов, хранимых процедур и функций, программного кода. Таким образом, нет необходимости обращаться к дорогостоящей команде разработки: аналитик, ведущий разработчик, программист/кодер, тестировщик, внедренец. Заявляемая группа изобретений используют уже готовый программный код и архитектурное решение в виде ограниченного набора примитивных блоков, из которых можно построить информационную систему любой сложности, обеспечивая универсальность системы, в которой зависимость затрат на сопровождение от сложности системы будет не хуже линейной. Это преимущество обеспечивается определенной избыточностью данных, поскольку в ней проиндексированы все хранящиеся данные, и вычислений, однако по стоимости эти затраты намного ниже временных и материальных затрат на содержание команды разработки. Самый главный риск — человеческий фактор при проектировании и реализации программного кода и базы данных — полностью исключен.

"Еще одна" EAV. Со всеми недостатками — но более того, совершенно не понятно, как реализуются "заявленные преимущества": например, как же достигается "уменьшение ошибок при вводе", учитывая, что механизм ограничений выкинули. Или почему кластеризация и шардинг проще, хотя теперь критерий шардинга не присутствует в каждой строчке.

Это не EAV, поэтому подразумеваемых вами недостатков тут нет.
Постарайтесь без клише обойтись и, если интересно, я расскажу по пунктам, что и как.
Статью старался не перегружать, потому что есть отдельные ссылки, где всё можно посмотреть и потрогать.
Все данные физически хранятся в одной таблице из 5 полей: ID, родитель (ID), тип (тоже ID), порядок среди равных (число), значение (набор байтов).

Не EAV, допустим. Тогда что? Ключ-значение с иерархией? Возьмите список недостатков от KV.


Ну и вопросов про ошибки и шардинг это все равно не отменяет.

Не KV, опять клише и притянутые автоматом недостатки.
Если бы это укладывалось в существующие приемы, то защитить решение патентом было бы нельзя.
Ошибки сокращаются за счет устранения рисков низкоуровневой работы с данными.
Шардинг проще опять же из-за предельно простой структуры данных.
И какие же у низкоуровневой работы с данными риски?
Не KV

Ну так а что тогда, собственно? Понимаете ли, "мы тут придумали такую клевую штуку, которая решает все ваши мечты, но мы вам про нее ничего не расскажем" — это не очень хороший подход для статьи.


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

Это все, простите, общие слова (которыми, к слову, пестрит маркетинговая документация практически любой СУБД). А конкретику можно какую-нибудь, которая бы их подтверждала?


Вот, возьмем, например, шардинг. Предположим, мне нужно шардить все данные по пользователю (а пользователей, соответственно, мы шардим по стабильному хэшу от гарантированно неизменного идентификатора; непривязанных к пользователю данных не существует). Как конкретно это делается в вашей системе, и почему это проще, чем во всех существующих?


Или возьмем консистентность. Как конкретно в вашей системе гарантируется ссылочная целостность, и почему это проще и лучше, чем в традиционной реляционной БД?

Предполагаю, что нужно просто в рамках одной транзакции прочитать данные, проверить ссылочную целостность и записать. Это значительно быстрее, чем проверять устаревшими средствами SQL сервера (на самом деле нет).


Ах да, транзакций же тоже нет. Тогда не знаю

Все данные физически хранятся в одной таблице из 5 полей: ID, родитель (ID), тип (тоже ID), порядок среди равных (число), значение (набор байтов).

Предположим, мне нужно сохранить тривиальную структуру: название книги и год ее выпуска. Какие конкретно записи появятся в вашей "одной таблице"?

Будет такая структура в Редакторе типов:


Так выглядит добавленный объект:


А так имевшиеся ранее и новые строчки в базе:

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

Добавятся строки метаданных (зеленым) и данных (синим)


Сама книга будет выглядеть в редакторе так:


А в Словаре этак:
Parent | ID  | Value
220    | 221 | 1923
220    | 224 | 670

А теперь объясните мне, почему это не EAV.

А при чем здесь этот фрагмент картинки?

Я вам совсем другое показывал, и вот то — не EAV.

При том, что это — EAV, и это нижний уровень. А, значит, вся ваша система как она есть сейчас построена поверх EAV, и (по умолчанию) несет все недостатки этого самого EAV.

При том, что это — EAV, и это нижний уровень.


Что «это»?

Вы выдрали кусок данных из контекста и строите неверную теорию.
Я говорю про принципиально иную структуру и иные методы, нежели это сделано в EAV.
Что «это»?

Ваше хранилище.


Я говорю про принципиально иную структуру

То есть данные в вашем хранилище имеют "принципиально иную структуру", нежели показанная вами же в примере выше? Так какую же, расскажите нам.

Ваше хранилище выглядит как EAV и крякает как EAV. Серьезно, если это не EAV — верю на слово, но в чем разница? Желательно техническими словами, а не маркетинговыми.

Ваше хранилище выглядит как EAV и крякает как EAV.

Я зачесываю волосы налево. По-вашему, я такой же зверюга, как Гитлер. Я, правда, ещё и рыжий. Ну, наверняка комик, скажете вы. А если я крякну?

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

Я же утверждаю, что это решение подходит для любых задач прикладной разработки. На небольших проектах подходит как есть, и я могу показать эти проекты. Для нормальных промышленных масштабов требует доработки, как и любая связка Язык программирования — База — Шаблонизатор — Хостинг. Но принципиально тоже подходит для выполнения проекта целиком.
По-вашему, я такой же зверюга, как Гитлер.

Ну какая глупость. Я же говорю, верю на слово, что отличается, но чем? От Гитлера вы, например, отличаетесь тем, что не возглавляете партию (и можно ещё сотню существенных отличий найти).


Ваше решение выглядит как СУБД поверх хранилища EAV. Во всяком случае на первый взгляд.


техническими словами EAV как таковой неработоспособен

Это не "технические слова", извините. Это как раз маркетинговый булшит — "как таковой неработоспособен".
Технический специалист из вашей команды может чуть более техническую статью написать? Математика, бенчмарки, примеры синтаксиса для сложных случаев. Мы же на Хабре всё-таки. Если есть, конечно, желание и время.

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

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

Я сделал выгрузку и анализ журналов одного из сервисов.
Это рекрутерский сервис, интегрированный с HH.RU: оттуда забираются анкеты кандидатов, хранятся вакансии, можно назначать встречи, отправлять СМС и письма.
Вчера там работал 21 пользователь, и они за день сделали чуть больше 10000 запросов на изменение, которые заняли в сумме 2.26 секунды согласно журналу:


Были еще запросы на выборку: построение рабочих форм, отчеты и прочее, которых гораздо больше.

То есть, это небольшая часть нагрузки с замерами.
Вот статистика по запросам (только изменение данных!) за весь день:


Это за самый нагруженный час:


Как видите, средний запрос отрабатывает меньше чем за треть миллисекунды, корреляции среднего времени отработки запроса с пиками нагрузки не наблюдается: за счет быстрой отработки запросов они просто не конфликтуют. Поэтому запас прочности достаточно велик.
и они за день сделали чуть больше 10000 запросов на изменение

… а сколько "запросов на изменение" у вас происходит, когда пользователь обновляет четыре свойства у одного объекта?

При создании, удалении и изменении — по 1 запросу на свойство, при удалении объекта — 1 запрос на все.

… то есть когда пользователь изменяет четыре свойства, вы шлете в четыре раза больше запросов на изменение, чем, гм, традиционные решения?

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

Вы правда хотите пообсуждать разницу в стоимости низкоуровневых и высокоуровневых операций?

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

"Быстро" — понятие очень относительное.


В собственном же откомпилированном движке это тем более будет работать на низком уровне с вполне конкурентноспособными характеристиками.

Если кто-то сможет его с этими характеристиками написать.

Если кто-то сможет его с этими характеристиками написать.
UltimaSol переизобрел структуру таблицы для хранения дерева данных объектов произвольной глубины, кстати уже неоднократно описанную во многих учебниках и статьях по БД.
Как я написал тут он просто не понимает насколько эта, на первый взгляд, компактная и простая структура хранения данных будет «дорога» при работе с ней на реальных объектах, для которых она действительно может потребоваться (потому что для большинства случаев она просто не нужна).
«любая база также внутри себя кладет изменения не единым действием, а адресно, по отдельным свойствам.» У вас категорически неверные сведения о «любой базе», для вас это пугало типа «обычного стирального порошка» от маркетологов (как и заявление «быстрее, выше, сильнее обычной базы»).

> Это быстро работает даже сейчас, при эмуляции всего процесса в базе данных, с громадным оверхэдом.

Как и говорил в другом месте — это возможно только при кривом проектировании вами «обычной» таблицы.

Спасибо. Теперь намного понятнее, на какую нишу вы позиционируетесь.


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

Ок, техническими словами EAV как таковой неработоспособен, если пытаться сделать приложение только средствами EAV

Прекрасно. Осталось объяснить нам, чем конкретно ваше решение отличается от EAV.


Я же утверждаю, что это решение подходит для любых задач прикладной разработки.

Утверждать-то можно что угодно.

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

Ещё: заявлено «повышение надёжности базы данных за счёт минимизации ошибок при добавлении новых данных», но при этом — нельзя задать CONSTRAINT'ы.

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

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


Первая часть предложения про программиста, а вторая — про администратора. У них совершенно разные задачи, и этот проект ориентирован больше на программиста, освобождая его от рутины.
В небольших проектах администратор вообще не нужен, что является как раз целью Интеграла (рабочее название этого проекта). Часто в любительской прикладной разработке при 100 тысячах записей в базе уже начинает всё тормозить и нужен админ.

Ещё: заявлено «повышение надёжности базы данных за счёт минимизации ошибок при добавлении новых данных», но при этом — нельзя задать CONSTRAINT'ы.


Речь идет о DDL — вы не можете ошибиться с размерностью данных, ключами и теми же CONSTRAINT'ами, если у вас нет доступа ко всему этому.

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


Заставьте программиста залезть в базу, найти ВСЕ тонкие места и починить. И починить правильно. Бизнес-пользователю такое удается редко, точнее, почти никогда.

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


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

А вы думаете, бизнес-пользователь способен построить правильную сущностную модель системы? Так нет, не способен. Тогда при чем тут бизнес-пользователь?

Как раз тут не про бизнес-пользователя, а про программиста: его не нужно заставлять делать неблагодарную, незаметную, не оплачиваемую отдельно работу, когда Интеграл почти всю её сделал за него.

Ну так не надо заставлять программиста делать неблагодарную и неоплачиваемую работу — просто заплатите ему.

Ага, известно чем это заканчивается. В одной компании, где я работал, шутили так:
Больше thread.sleep'ов ставьте в коде, за скорость отдельно заплатят уроды.
Спасибо за разъяснения, но у меня всё равно осталась путаница. Что входит в обязанности администратора, программиста и бизнес-пользователя?

Выглядит так, что вы поверх SQL сервера сделали свой небольшой SQL сервер, и типа он будет работать быстрее (на самом деле нет).

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

Насчет быстрее: я не говорю, что быстрее, чем обычная РСУБД. А говорю, что устраняю непродуктивные накладные расходы и риски за счет добавления некоторой избыточности. Чтобы админу не приходилось искать узкие места и «добавлять индексы» в работающей системе, а сделать эту работу за него (это только одна из задач).
А говорю, что устраняю непродуктивные накладные расходы и риски за счет добавления некоторой избыточности

А избыточность, значит, не добавляет накладных расходов?

сделать эту работу за него

А кто будет делать эту работу за него? Программист? Или автоматический оптимизатор? Непонятно пока.

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

Т.е. оптимизатор автоматический? Хорошо. В mysql или posrgres так же используются оптимизаторы для построения плана запроса. Какие вы видите преимущества в вашем проекте по сравнению с ними?


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

Т.е. оптимизатор автоматический? Хорошо. В mysql или posrgres так же используются оптимизаторы для построения плана запроса. Какие вы видите преимущества в вашем проекте по сравнению с ними?


Мой проект сегодня использует оптимизатор mysql или posgre, т.е. любой базы, на которой развернуто ядро. Даже когда у Интеграла будет свой оптимизатор, то он не будет сильно отличаться от них, а скорее будет просто взят у этих уважаемых коллег. Преимущество не в оптимизаторе, а в системе организации хранения данных и способе представления их пользователю.

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


Пример с пятью миллионами объектов, что составляет 31 872 291 строку в представленной здесь архитектуре.
Можете попробовать сделать аналог в классической СУБД (или найти существующий, коих полно), который будет работать в 10 раз быстрее.
А сколько весит таблица и индекс для КЛАДРа?
Кладр весом в 320МБ в плоских файлах будет весить 500МБ в классической СУБД с индексами по популярным полям поиска и 1500МБ в Интеграле, где проиндексировано всё. Порядок чисел таков.

Вы предлагаете это сделать мне? Повторюсь, это очень странное предложение. Мне интересно посмотреть на сравнительный бенчмарк (если он есть или вы планируете его сделать). Делать бенчмарк для вас мне, конечно, не интересно.


P.S. найти у вас "Селезневская, 10" не вышло, хотя такой адрес явно есть.

Вы предлагаете это сделать мне? Повторюсь, это очень странное предложение. Мне интересно посмотреть на сравнительный бенчмарк (если он есть или вы планируете его сделать).

Предлагаю просто посмотреть визуально как это работает. Если у вас на памяти есть подобный сервис, можете на глазок попытаться определить разницу. Нет, так нет.
Я делал сравнение с подобным сервисом в классической СУБД, получалась разница в 2-4 раза по разным оценкам.

P.S. найти у вас «Селезневская, 10» не вышло, хотя такой адрес явно есть.

Там тоже есть P.S.:
P.S. Сервис немного глючноват в плане перебора комбинаций (все таки его суть не в этом), предложения по исправлению с благодарностью принимаются.
Ядро сделает работу: создаст структуру и перестроит индексы

И где гарантии, что оно построит индексы правильно?


(Вот у MS в Azure для таких оптимизаций прикручено наблюдение за статистикой в очень больших объемах и модель машинного обучения. И то они автооткат сделали.)

А там всего 3 индекса на всё, сложно сделать неправильно.

Я не первый, кто пытался заставить работать такую архитектуру. Есть эпичные случаи, но у парней не особо получалось. Azure идет путём тех парней, применяя танковые клинья и ковровое бомбометание наблюдение в очень больших объемах и модель машинного обучения, я — своим, упрощая всё.
А там всего 3 индекса на всё, сложно сделать неправильно.

Всегда три индекса? А как же write vs read? Покрывающие индексы, разные виды деревьев, пространственные, прочая смешная требуха?


One size doesn't fit all.

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

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

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

Нет-нет, что вы!


Хотя, архитектуру определяет один человек, и от него зависит успех отдела-другого программистов. Плюс часто вмешивается начальство, сроки, политики, неудачно выбранный ранее инструмент и так далее.

Хотя, архитектуру определяет один человек

Не везде это так.

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

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

> Сложность вполне решаемая.

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

А напомните еще раз, как вы строите индексы по строковым значениям длиннее килобайта?

И какой тип индекса используется?

Сейчас вы будете писать, что мы типа не разобрались.
Ну давайте будем разбираться.
Ваша структура поддерживает SQL запросы?

Есть построитель запросов, аналог SQL, там тот же принцип: перечисляете нужные вам поля данных из разных таблиц, ядро их связывает в запрос и выводит результат. Если связать можно разными способами (например, заказчик и подрядчик у договора хранятся в одной таблице юр.лиц), то вы можете указать, по каким полям нужна связь.
Статье есть пара ссылок на примеры, как это делается: вот и вот.

А группировка там есть? Having?
Приведите пример, во что транслируется запрос «все авторы с двумя или более книгами» на вашей базе.

Есть аналог HAVING.

Запрограммированный отчет в интерфейсе будет выглядеть примерно так:


В базу улетит примерно такой запрос:
SELECT a227.val v1_217,COUNT(a217.val) v2_217 
FROM test a217 
LEFT JOIN (test r227 JOIN test a227) ON r227.up=a217.id AND a227.id=r227.t AND a227.t=225 
WHERE a217.up!=0 AND a217.t=217 
GROUP BY v1_217 
HAVING v2_217>=99999999 AND v2_217<=2


Как это делается можно также посмотреть на видео (полторы минуты).
В пред статьях было написано что интеграл построен на PHP + MySQL. Как оно может работать быстрее MySQL?
Легко — делаете крайне неоптимальную структуру на MySSQL в сравнительном тесте и…
Кажется, я понял. Автор изобрёл не EAV и не ORM, а дерево типов, а также способ уложить его в таблицу. Очень знакомо. Удивительно, что такую тривиальность можно запатентовать. UltimaSol, можно ссыль на патент или просто вложите сюда текст.
Спасибо, коллега! Вы первый комментатор, кто вдумался о чем речь.
На самом деле, запатентовать можно что угодно, и в ходе патентного поиска я насмотрелся всякого. Гораздо сложнее добиться практической работоспособности, и я начинал именно с неё.
Ссыль
Но ведь такая конструкция возникает во всякой более-менее развитой информационной системе: медицинской (сам видел), логистической (догадываюсь) и т.д. И тогда встаёт два вопроса: (а) если такое уже есть и используется, зачем это изобретать; (б) кто-то может оспорить патент по праву более раннего фактического использования всей этой хурмы.
Но ведь такая конструкция возникает во всякой более-менее развитой информационной системе

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

Вы-то не видели, а я на рубеже века разработал систему со схожим механизмом хранения и успешно ее внедрил как минимум дважды.

Т.е. вы пробовали EAV и отчаялись еще на рубеже века, пару раз внедрив. Ваш негатив понятен.
Моё первое внедрение этой системы состоялось в 2006 году, и она там до сих пор работает.

… а я где-то говорил, что отчаялся? Та ни, я EAV до сих пор использую.

UFO just landed and posted this here
Да все лепили подобные костыли, именно поэтому такая реакция у читателей.
UFO just landed and posted this here
>Спасибо, коллега! Вы первый комментатор, кто вдумался о чем речь.

Удивительно то, что читателям приходится гадать, что именно автор статьи имел ввиду. Тут естественно кто-то угадает, кто то нет…

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

Может вы нам можете объяснить, чем показанная в комментариях выше структура хранения данных для конкретного объекта отличается от EAV?

Да бог с вами, назовите это EAV, если вам так лучше.
EAV и Интеграл ничем не отличается в плане хранения всех атрибутов в одной таблице.
В EAV, наверное, тоже есть встроенный редактор типов, там можно работать с миллионами записей, произвольно создавать структуры данных, писать запросы, которые реализуют любые конструкции SQL и всё такое.
Да EAV, чё…
там [в EAV] можно работать с миллионами записей, произвольно создавать структуры данных, писать запросы, которые реализуют любые конструкции SQL и всё такое.

Можно, конечно.


Ну а встроенный редактор типов — это, извините, как ваша "экосистема": "учитывая простоту архитектуры, адаптация этих средств под конкретный проект сопоставима с написанием их с нуля". В том смысле, что если кто-то построил (как я в свое время) фреймворк на базе EAV, то редактор типов там был второй реализованной задачей (и она тривиальна).


Да EAV, чё…

Да я же не против, я искренне спрашиваю "в чем отличия", только пока что-то никто не рассказывает.

Более высокий уровень абстракции — как множества vs категории. Это красиво и, время от времени, идеологически необходимо.

А более конкретно? Я выше уже приводил пример:


Parent | Type | Value
220    | 218  | 1923
220    | 223  | 670

(это реальная структура хранения от автора статьи)


Каким образом это более высокий уровень абстракции, чем EAV? Тем, что названия поменяли? Ну так с точки зрения имплементации ничего не поменялось. Тем, что можно хранить произвольной глубины иерархию для объекта? Так там нет оптимизации для выборки объектов произвольной глубины.

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

Лично меня вряд ли может, потому что в этом клубе джентельменам на слово не верят.

И лишиться патентов, которые получены минимум на 20 лет позже разработанного? Новизны-то в них не окажется.
там нет оптимизации для выборки объектов произвольной глубины
Уверен что UltimaSol даже не представляет как это его «изобретение» будет жрать как не в себя ресурсы и жутко тормозить на т.н. рекурсивных запросах к этой единственной таблице если таких объектов произвольной глубины будет в ней достаточно много. Думаю уже ста тысяч хватит чтобы все просто умерло даже на самом крутом железе.
Вполне представляю и могу вам показать — см. комментарий выше.

Статистика взята из сервиса, где одновременно работают от 15 до 30 человек, в работе у них больше 50 тысяч кандидатов.
Сервер самый простой: стоимость менее 25$ в год, 1 ядро @2.5MHz, RAM 1Gb.
Вы хоть понимаете о чем речь?
Где в этом сервисе объекты произвольной глубины?
Как вы их ищете по атрибуту, который может быть на ЛЮБОМ уровне в ЛЮБОЙ ветке дерева данных такого объекта?
Как вы в конце концов извлекаете и собираете такие объекты, где чтения данных КАЖДОГО уровня КАЖДОЙ ветки требуется ОТДЕЛЬНЫЙ запрос к БД?
Вы хоть понимаете о чем речь?
Где в этом сервисе объекты произвольной глубины?

Немного понимаю. Вот, ниже структура таблиц, как она видна программисту в этом сервисе:


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

Глубина структуры может быть какой угодно, это ограничено только объемом, предоставленным железом, и на быстродействие не влияет сколько-нибудь существенно.

Как вы их ищете по атрибуту, который может быть на ЛЮБОМ уровне в ЛЮБОЙ ветке дерева данных такого объекта?
Как вы в конце концов извлекаете и собираете такие объекты, где чтения данных КАЖДОГО уровня КАЖДОЙ ветки требуется ОТДЕЛЬНЫЙ запрос к БД?


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

Вот, ниже структура таблиц, как она видна программисту в этом сервисе:

Я что-то в этой структуре глубины больше двух-то и не вижу.


Так и ищу, по коду типа. Индекс выводит меня прямо к нужному листу нужной ветки, не пробегаясь по всему дереву.

Дадада, вот только теперь как от этого листа в один запрос попасть к соответствующему началу дерева?


Грубо говоря, представьте себе, что у вас есть "авторы", у них есть вложенные сущности "книги" (да, в рамках этой задачи у каждой книги есть только один автор, и книги без авторов не бывает; "вложенная" — это когда parent этой сущности — это другая сущность), у "книги" есть вложенная сущность "глава", у "главы" — "страница", у "страницы" — "абзац", а вот в "абзацах" бывают "термины". Вот получили в в один запрос нужный "термин" — а теперь можете ли вы в один запрос сказать, у какого автора он встретился? А если задачу немного — совсем немного — усложнить, и сказать, что под "книгой" бывают "разделы", а под "разделами" — другие "разделы", и так до бесконечности, а вот уже в "разделах" — "термины"?

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

Эээ, конечно же, нет. Если система заточена под иерархии (как видно из вашего ответа, ваша — не заточена), то будет не больше одного JOIN.


Точно такой же запрос с тем же количеством JOIN'ов будет выполнен и в этой архитектуре — один запрос.

… так что же делать, если количество уровней неизвестно?

Вы о чем сейчас? Приведите пример, пожалуйста.
Это решение эмулирует РСУБД и её возможности.

Я сейчас о способах хранения древовидных структур в БД — которых даже для РСУБД не меньше трех (а еще ведь есть нереляционные БД).


Собственно, все, что я хотел увидеть — это то, что на хранение именно древовидных структур ваша система тоже не заточена.

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

Вот, собственно, и ответ на "автор изобрёл [...] дерево типов". Что и требовалось доказать.


Повторюсь в очередной раз, система решает задачу РСУБД в общем

Эм, зачем решать задачу РСУБД, если есть РСУБД?


без экзотики и спецнаправлений.

Древовидные структуры — это нифига не экзотика.

Вы уже, вроде, давно перешли на ваши личные заморочки. В статье четко указано что это и зачем.

В том-то и беда, что ни что, ни как, ни зачем в статье не указано. Обо всем приходится гадать.

Вот, ниже структура таблиц, как она видна программисту в этом сервисе

Подскажите, какой запрос (на SQL) летит в базу, если мы хотим найти все вакансии, на которые откликнулись кандидаты с фамилией "Иванов", и вывести город, зарплату от/до, и работодателя вакансий. С разделением по страницам, естественно.

Примерно такой запрос, как ниже.
Количество записей на странице определяется параметром отчета, номер страницы передается также параметром.
SELECT a330.val v1837447_321,a208.val v1837452_0,a236.val v1837453_208,a260.val v1837454_208,a261.val v1837455_208,a210.val v1837456_0 
FROM hr4hr a209 
LEFT JOIN (hr4hr r321 JOIN hr4hr a321 ) ON r321.up=a209.id AND a321.id=r321.t AND a321.t=321 
LEFT JOIN hr4hr a330 ON a330.up=a321.id AND a330.t=330 LEFT JOIN hr4hr a208 ON a208.t=208 AND a209.up=a208.id 
LEFT JOIN (hr4hr r236 JOIN hr4hr a236 USE INDEX (PRIMARY)) ON r236.up=a208.id AND a236.id=r236.t AND a236.t=234 
LEFT JOIN hr4hr a260 ON a260.up=a208.id AND a260.t=260 
LEFT JOIN hr4hr a261 ON a261.up=a208.id AND a261.t=261 
LEFT JOIN hr4hr a210 ON a210.t=210 AND a208.up=a210.id 
WHERE a209.up!=0 AND a209.val!='' AND a209.t=209 AND a330.val ='Иванов'
LIMIT 10,20

При всем уважении, даже банальный grep по файлу на 50 тысяч строк для 15, 30, да хоть сотни пользователей, спокойно справится на самой простой маломощной машине. Правильно понимаю, что в задаче никаких JOIN хотя бы нет? Вы же понимаете, что с таким объемом у вас раскладные расходы на сеть и подключение к БД выше, чем расходы этой самой базы?

Правильно понимаю, что в задаче никаких JOIN хотя бы нет? Вы же понимаете, что с таким объемом у вас раскладные расходы на сеть и подключение к БД выше, чем расходы этой самой базы?

JOIN есть для каждого атрибута, поэтому в базу летит один сравнительно короткий запрос на весь набор данных.
(это реальная структура хранения от автора статьи)


Нет, это обрезанная версия, зачем передергиваете, «джентльмен»?

Я, вроде, нигде и не говорил, что она полная.


А, главное, если опущенные мной фрагменты влияют на классификацию — то вы покажите, как именно.

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

(1) у вас есть индекс на поле Order, который "принципиально меняет план запроса к базе"?
(2) выкинутое мное поле ID влияет на план запроса к БД (на самом деле — не всегда), но не на классификацию. Но вообще, конечно, да, для запроса конкретного свойства это поле очень нужно — чтобы добавить в план запроса key lookup и джойн… вы же покрывающие индексы строить отказываетесь, хотя они бы избавили вас от лишней ветки.

вы же покрывающие индексы строить отказываетесь, хотя они бы избавили вас от лишней ветки.

… ну да, так и есть, добавление в индексы INCLUDE резко улучшило план запросов (пять index seek, ни одного скана, ни одного key lookup).

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

О, кстати, о "решаются проще". Есть, значит, простая задачка: у меня есть книги и есть их содержимое (текст + источник + еще несколько полей). Я хочу, чтобы данные по книгам лежали на SSD, а их содержимое (очевидно, этих данных больше на несколько порядков, но зато они намного реже используются) лежали на HDD. Как это сделать в MS SQL с традиционной схемой, я хорошо знаю и представляю. А как это сделать в вашем решении мечты?

Все данные физически хранятся в одной таблице из 5 полей: ID, родитель (ID), тип (тоже ID), порядок среди равных (число), значение (набор байтов). У неё есть 3 индекса: ID, тип-значение, родитель-тип.

И еще раз кстати. А как вы решаете ту проблему, что далеко не все значения вообще можно проиндексировать (например, в MS SQL в индекс нельзя включить поля длинее 900 байт, в InnoDB есть аналогичные ограничения)?

Эта общая особенность любой БД, не мне её решать и уж точно не в рамках этой задачи.

Во-первых, не любой.
Во-вторых, если вы ее не решили, то ваши заявления про индекс по Value невозможны, потому что без решения этой проблемы такие индексы построить нельзя.

… я, значит, не поленился и создал маленькую тестовую БД. Схема тривиальна: авторы-книги, у автора только имя, у книги — автор, название, год и число страниц. 100 тысяч авторов, для каждого автора от 1 до 25 книг. Таблицу из поста воспроизвел как понял на основании описания в посте, комментах и патенте.


Сначала просто статистика по объему: в таблице с авторами — 100k строк, с книгами — ~1.25m строк, в плоской таблице — ~6.5m. По объему, соответственно, 8, 141 и 536 Мб. Если кто-то думает, что место нынче бесплатно, то нет.


Ну а теперь запросы. Начнем с авторов, у которых в имени есть 5300: select Name from Authors where Name like '%5300%'. 20 записей, никаких чудес, index scan (индекс по имени автора, конечно же, есть, но толку от него здесь пренебрежимо мало). CPU time = 234 ms, elapsed time = 242 ms. Добавим идентификатор: `select Id, Name...: время не изменилось, план выполнения не изменился. Пока все предсказуемо.


Теперь все то же самое на плоской таблице: select Value from Flat where Value like '%5300%' and Type = 705712. В плане выполнения — index seek с критерием по типу, число прочтенных строк (как и выше) — 100k. Время выполнения тоже не отличается. Добавим идентификатор: select ParentId, Value.... Время выполнения подросло: CPU time = 219 ms, elapsed time = 314 ms, в плане выполнения появился key lookup и join (еще бы, никто же не озаботился покрывающим индексом на ParentId), но пока еще терпимо — неудивительно, все на SSD, памяти много, ресурсов хватает всем и на всё.


Ладно, давайте посмотрим на книги этих авторов.


select Authors.Id, Authors.Name, Books.Id, Books.Name, Books.Pages, Books.Year
from Authors 
    inner join Books on Authors.Id = Books.AuthorId
where Authors.Name like '%5300%'

308 строк, CPU time = 218 ms, elapsed time = 765 ms, в плане выполнения — index scan (авторы), index seek (книги по авторам) и key lookup (сами книги). Все предсказуемо, как топор.


А теперь...


select AuthorName.ParentId, AuthorName.Value, BookAuthorId.ParentId, BookName.Value, BookYear.Value, BookPages.Value
from Flat AuthorName
    inner join Flat BookAuthorId on BookAuthorId.Type = 705715 and BookAuthorId.Value = AuthorName.ParentId
    inner join Flat BookName on BookName.Type = 705717 and BookName.ParentId = BookAuthorId.ParentId
    inner join Flat BookYear on BookYear.Type = 705719 and BookYear.ParentId = BookAuthorId.ParentId
    inner join Flat BookPages on BookPages.Type = 705721 and BookPages.ParentId = BookAuthorId.ParentId
where AuthorName.Type = 705712 and AuthorName.Value like '%5300%'

308 строк на выходе. CPU time = 1641 ms, elapsed time = 2117 ms. В плане выполнения — два полных скана таблицы и три пары index seek/key lookup (ну и соответствующее количество джойнов). И это у нас всего шесть полей в выводе.


Снижение риска деградации производительности, говорили они...

И здесь вы всё переврали, не повторив таблицу из 5 полей с 3 индексами. Но в этот раз ваш косяк виден как на ладони.

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

Я тоже сделал табличку с 1048552 книгами (сколько влезло на лист экселя) и 142654 авторами.

Книги:


Авторы:


Также я сделал отчет, но не писал SQL, а набрал нужные поля и сразу вписал условие (перебрал их несколько, пока не получил не менее 300 и не более 1000 результатов):


Последнее условие вернуло такой результат — 465 строк с авторами по маске, к которой неприменим индекс:


Все запросы при построении отчета, а их было 6 штук (проверка токена пользователя, поиск отчета, сбор метаданных, выполнение отчета), выполнились за 124.3 мс, из которых 121.3 мс заняло выполнение собственно запроса для отчета.

Сам запрос получился такой:
SELECT a225.val v1_225,a217.val v2_217,a223.val v3_217,a219.val v4_217
FROM test a225
LEFT JOIN (test r217 JOIN test a217 USE INDEX (PRIMARY)) ON r217.up=a217.id AND a225.id=r217.t AND a217.t=217
LEFT JOIN test a223 ON a223.up=a217.id AND a223.t=223 
LEFT JOIN test a219 ON a219.up=a217.id AND a219.t=219 
WHERE a225.up!=0 AND length(a225.val) AND a225.t=225 AND a225.val LIKE '%aro%'


План его выполнения:
Но в этот раз ваш косяк виден как на ладони.

Да? И в чем же он конкретно?


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

Докажите.

Да? И в чем же он конкретно?

Докажите.

По существу: по таймингу или плану запроса есть замечиния?
Иначе слив засчитан.
По существу: по таймингу или плану запроса есть замечиния?

Есть, конечно. Никого не интересует абсолютный тайминг, интересует сравнительный. Равно как и планы запросов на разных СУБД сравнивать бесполезно.

Ок, сделаю сравнение таймингов и планов этих двух подходов на одном сервере.
Вы бы лучше дамп базы скинули. Чтобы все могли повторить тесты на тех же данных.
Вы приводите часть некоей структуры, которую никак нельзя трансформировать в мою обратимыми преобразованиями (перестановка полей, транспонирование таблиц, декомпозиция и объединение и т.д.)

В патенте есть таблица 3. Там в колонке «Комментарий» указано назначение данных. Данные можно разнести по таблицам системы Magento 2 в соответствии с их назначением.

Корневой элемент — не нужен
Базовые типы данных — наличие таблиц catalog_product_entity_varchar, catalog_product_entity_int, ...
Произвольные типы данных — eav_attribute_set / eav_entity_type
Реквизиты произвольных типов — eav_entity_attribute / eav_attribute
Данные сущностей верхнего уровня — catalog_product_entity
Значения атрибутов — строки таблиц catalog_product_entity_varchar, catalog_product_entity_int, ...

Я взял Magento 2 c Github. Также взял пример таблицы из патента. Последней строки нет, так как там ссылка на данные, которых нет в таблице.

SQL
INSERT INTO `single_table` (`id`, `parent_id`, `type_id`, `value`, `order`) VALUES
(1, 1, 1, 'Root', 0),
(2, 0, 13, 'Договор', 0),
(3, 0, 8, 'Заказчик', 0),
(4, 0, 13, 'Счет', 0),
(5, 0, 15, 'Сумма', 0),
(8, 0, 8, 'CHARS', 0),
(9, 0, 9, 'DATE', 0),
(11, 0, 11, 'BOOLEAN', 0),
(13, 0, 13, 'NUMBER', 0),
(14, 0, 3, '', 0),
(15, 0, 15, 'SIGNED', 0),
(18, 0, 9, 'Дата', 0),
(19, 2, 18, '', 1),
(20, 2, 22, '', 2),
(21, 0, 8, 'Продукт', 0),
(22, 0, 8, 'Предмет договора', 0),
(23, 0, 15, 'Цена', 0),
(24, 0, 15, 'Себестоимость', 0),
(25, 2, 23, '', 3),
(26, 2, 14, '', 4),
(28, 21, 23, '', 5),
(29, 21, 24, '', 6),
(1181, 1, 2, '1161 (договор)', 1),
(3561, 1181, 18, '20060602 (дата)', 1),
(3562, 1181, 22, 'Проведение работ (предмет договора)', 2),
(3563, 1181, 23, '40000 (сумма)', 3);



Несколькими запросами можно преобразовать данные из одной структуры в другую, причем так, что веб-интерфейс Magento будет корректно с ними работать. Запросы ниже.




В запросах я сделал преобразование только в varchar, поэтому обратное преобразование тоже только в CHARS. Для proof of concept этого достаточно.
Так как таблицы Magento не пустые, я добавил смещение всех id на некоторую константу.
Все данные помещаются в таблицу catalog_product_entity, но теоретически можно использовать eav_entity_type для более точного разделения сущностей.

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

Прямое преобразование
/* id_offset is not required for empty tables, magento tables are not empty */
SET @id_offset = 10000;


INSERT INTO eav_attribute_set (attribute_set_id, attribute_set_name, entity_type_id)
SELECT derived_types.id + @id_offset,
    IF(derived_types.value != '', derived_types.value, CONCAT('ref_', refs.value)),
    4 AS magento_product_entity_type
FROM single_table derived_types
    LEFT JOIN single_table refs ON refs.id = derived_types.type_id
WHERE derived_types.parent_id = 0 AND derived_types.id != derived_types.type_id
ORDER BY derived_types.id;


INSERT INTO eav_attribute_group (attribute_group_id, attribute_set_id, attribute_group_name, attribute_group_code)
SELECT attribute_set_id, attribute_set_id, 'General', 'general'
FROM eav_attribute_set
WHERE attribute_set_id > @id_offset;


INSERT INTO eav_attribute (attribute_id, attribute_code, frontend_label, backend_type, entity_type_id, frontend_input, is_user_defined)
SELECT type_attributes.id + @id_offset,
    CONCAT(LOWER(IF(attribute_type_names.value != '', attribute_type_names.value, CONCAT('ref_', refs.value))), '_', type_attributes.id) AS workaround_for_unique,
    IF(attribute_type_names.value != '', attribute_type_names.value, CONCAT('ref_', refs.value)),
    'varchar', 4 AS magento_product_entity_type, 'text', 1
FROM single_table derived_types
    INNER JOIN single_table type_attributes ON type_attributes.parent_id = derived_types.id
    INNER JOIN single_table attribute_type_names ON attribute_type_names.id = type_attributes.type_id
    LEFT JOIN single_table refs ON refs.id = attribute_type_names.type_id
WHERE derived_types.parent_id = 0 AND derived_types.id != derived_types.type_id
ORDER BY derived_types.id;


INSERT INTO catalog_eav_attribute (attribute_id)
SELECT attribute_id
FROM eav_attribute
WHERE eav_attribute.attribute_id > @id_offset;


INSERT INTO eav_entity_attribute (sort_order, attribute_set_id, attribute_group_id, attribute_id, entity_type_id)
SELECT type_attributes.`order`,
    derived_types.id + @id_offset,
    derived_types.id + @id_offset,
    type_attributes.id + @id_offset,
    4 AS magento_product_entity_type
FROM single_table derived_types
    INNER JOIN single_table type_attributes ON type_attributes.parent_id = derived_types.id
    INNER JOIN single_table attribute_type_names ON attribute_type_names.id = type_attributes.type_id
WHERE derived_types.parent_id = 0 AND derived_types.id != derived_types.type_id
ORDER BY derived_types.id;


INSERT INTO catalog_product_entity (entity_id, attribute_set_id, sku)
SELECT objects.id + @id_offset, objects.type_id + @id_offset, objects.value
FROM single_table objects
WHERE objects.parent_id = 1 AND objects.id != 1
ORDER BY objects.id;


INSERT INTO catalog_product_entity_varchar (value_id, attribute_id, entity_id, value)
SELECT attribute_values.id + @id_offset, type_attributes.id + @id_offset, objects.id + @id_offset, attribute_values.value
FROM single_table objects
INNER JOIN single_table attribute_values ON attribute_values.parent_id = objects.id
INNER JOIN single_table type_attributes ON type_attributes.parent_id = objects.type_id AND type_attributes.type_id = attribute_values.type_id
WHERE objects.parent_id = 1 AND objects.id != 1;


Обратное преобразование
SET @id_offset = 10000;


-- INSERT INTO single_table (id, parent_id, type_id, value, order)

SELECT 1 as id, 1 as parent_id, 1 as type_id, 'Root' as value, 0 as `order`
UNION ALL


SELECT 8, 0, 8, 'CHARS', 0
UNION ALL


SELECT
    attribute_set_id - @id_offset AS id,
    0,
    8,
    attribute_set_name,
    0
FROM eav_attribute_set
WHERE attribute_set_id > @id_offset
    AND POSITION('ref_' in attribute_set_name) = 0

UNION ALL


SELECT
    s1.attribute_set_id - @id_offset AS id,
    0,
    s2.attribute_set_id - @id_offset AS id,
    '',
    0
FROM eav_attribute_set s1
	INNER JOIN eav_attribute_set s2 ON s2.attribute_set_name = SUBSTR(s1.attribute_set_name, 5) AND s2.attribute_set_id > @id_offset
WHERE s1.attribute_set_id > @id_offset
    AND POSITION('ref_' in s1.attribute_set_name) = 1

UNION ALL


SELECT ea.attribute_id - @id_offset, ea.attribute_set_id - @id_offset, s2.attribute_set_id - @id_offset, '', ea.sort_order
FROM eav_entity_attribute ea
    INNER JOIN eav_attribute a ON a.attribute_id = ea.attribute_id
    INNER JOIN eav_attribute_set s2 ON s2.attribute_set_name = a.frontend_label AND s2.attribute_set_id > @id_offset
WHERE ea.attribute_set_id > @id_offset

UNION ALL


SELECT entity_id - @id_offset, 1, attribute_set_id - @id_offset, sku, 1
FROM catalog_product_entity
WHERE entity_id > @id_offset

UNION ALL


SELECT ev.value_id - @id_offset, ev.entity_id - @id_offset, s2.attribute_set_id - @id_offset, ev.value, ea.sort_order
FROM catalog_product_entity_varchar ev
    INNER JOIN eav_attribute a ON ev.attribute_id = a.attribute_id
    INNER JOIN eav_attribute_set s2 ON s2.attribute_set_name = a.frontend_label AND s2.attribute_set_id > @id_offset
    INNER JOIN eav_entity_attribute ea ON ea.attribute_set_id = s2.attribute_set_id AND ea.attribute_id = a.attribute_id
WHERE entity_id > @id_offset

UNION ALL


SELECT ev.value_id - @id_offset, ev.entity_id - @id_offset, s2.attribute_set_id - @id_offset, ev.value, ea.sort_order
FROM catalog_product_entity_varchar ev
    INNER JOIN eav_attribute a ON ev.attribute_id = a.attribute_id
    INNER JOIN eav_attribute_set s2 ON s2.attribute_set_name = a.frontend_label AND s2.attribute_set_id > @id_offset
    INNER JOIN catalog_product_entity e ON e.entity_id = ev.entity_id
    INNER JOIN eav_entity_attribute ea ON ea.attribute_set_id = e.attribute_set_id AND ea.attribute_id = ev.attribute_id
WHERE ev.entity_id > @id_offset
;

А можете перечислить индексы (включая кластерный), которые созданы на таблице значений в Magento? А то я попробовал прочитать их DSL для создания таблицы, но не уверен, что все там правильно понял.

Скрытый текст
CREATE TABLE `catalog_product_entity_varchar` (
	`value_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Value ID',
	`attribute_id` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Attribute ID',
	`store_id` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Store ID',
	`entity_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Entity ID',
	`value` VARCHAR(255) NULL DEFAULT NULL COMMENT 'Value',
	PRIMARY KEY (`value_id`),
	UNIQUE INDEX `CATALOG_PRODUCT_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_STORE_ID` (`entity_id`, `attribute_id`, `store_id`),
	INDEX `CATALOG_PRODUCT_ENTITY_VARCHAR_ATTRIBUTE_ID` (`attribute_id`),
	INDEX `CATALOG_PRODUCT_ENTITY_VARCHAR_STORE_ID` (`store_id`),
	CONSTRAINT `CATALOG_PRODUCT_ENTITY_VARCHAR_STORE_ID_STORE_STORE_ID` FOREIGN KEY (`store_id`) REFERENCES `store` (`store_id`) ON DELETE CASCADE,
	CONSTRAINT `CAT_PRD_ENTT_VCHR_ATTR_ID_EAV_ATTR_ATTR_ID` FOREIGN KEY (`attribute_id`) REFERENCES `eav_attribute` (`attribute_id`) ON DELETE CASCADE,
	CONSTRAINT `CAT_PRD_ENTT_VCHR_ENTT_ID_CAT_PRD_ENTT_ENTT_ID` FOREIGN KEY (`entity_id`) REFERENCES `catalog_product_entity` (`entity_id`) ON DELETE CASCADE
);

Спасибо.


MySQL создает кластерный индекс по primary key? Я, собственно, не мог понять, в реализации Magento он будет по value_id или по (entity_id, attribute_id, store_id).

По value_id. Если есть первичный ключ, создается по нему.

Спасибо. Я так и думал, но надо было уточнить.

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


Структура не является изобретением, что делает неверным ваши последующие выводы.

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

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

Опишите, в чем отличия? Я утверждаю, что это не бессвязный массив каких-то данных. Как минимум потому что иначе он не обрабатывался бы существующим движком коммерческой системы, который вряд ли сделан для работы с бессвязными массивами данных.


Что за «Договор» у вас в выпадающем списке?

А что за договор у вас в списке сущностей на скриншотах схемы данных? Это набор атрибутов, в терминах вашей системы это тип. Можно сделать такой веб-интерфейс, который не будет его делать выпадающим списком. Или можно ваш интерфейс поменять так, чтобы он type_id выводил выпадающим списком.


то есть, вам нужно хардкодить где какой атрибут хранится и как к нему обращаться. Это иной принцип хранения и выборки

Вы писали:


"Если, например, кто-то сделает отдельные таблицы под разные типы (и размерность) данных, чтобы работал индексируемый поиск по диапазонам чисел, и будет делать JOIN разных таблиц, в зависимости от базового типа данных, то это будет в рамках этого патента."


catalog_product_entity_varchar, catalog_product_entity_int… это отдельные таблицы для типа данных. Если вы считаете, что иной, опишите все отличия от вашего принципа. Чтобы по этому списку отличий можно было проверить любой другой принцип хранения и выборки на нарушение или ненарушение вашего патента.


Структура не является изобретением, что делает неверным ваши последующие выводы.

Я писал на основе того, что вы писали сами касательно рамок патента. В том числе "Патентом защищена система: структура из 4 полей (Order — необязательное поле) с этими индексами".

catalog_product_entity_varchar, catalog_product_entity_int… это отдельные таблицы для типа данных. Если вы считаете, что иной, опишите все отличия от вашего принципа. Чтобы по этому списку отличий можно было проверить любой другой принцип хранения и выборки на нарушение или ненарушение вашего патента.

Хорошо, я составлю краткий список для обнаружения отличий — простой опросник на одну-две минуты.
Если вы считаете, что иной, опишите все отличия от вашего принципа. Чтобы по этому списку отличий можно было проверить любой другой принцип хранения и выборки на нарушение или ненарушение вашего патента.


Опубликовал ответ здесь
В статье описана не структура, а подход к организации данных — мы храним единообразно все типы, все мета-данные, все данные и их связи. Это позволяет не писать код, конфигурируя структуру данных и задавая выборки.

Эгм. "Не писать код" позволяет визуальный конфигуратор, а не подход к организации данных.

Sign up to leave a comment.

Articles