Comments 47
Главный минус такого решения — сложность конкурентных изменений.
+4
Не больше, чем в EAV.
0
Значительно больше. При EAV меняется строка в таблице, при XML — надо целиком переписывать документ. Таким образом, два разных запроса могут поменять при EAV без проблем конкурентно, а при XML — один переписывает документ целиком, потом второй.
+2
Согласен.
Но многие приложения, которые я видел, в любом случае выполняли UPDATE всей строчки, даже если данные во ходной форме изменились только в одном поле, или вообще не изменились. Это конечно не правильно.
Но многие приложения, которые я видел, в любом случае выполняли UPDATE всей строчки, даже если данные во ходной форме изменились только в одном поле, или вообще не изменились. Это конечно не правильно.
0
Теоретически и xml-документ можно обновлять только частично, новыми данными (например контроль на триггерах и т.д.).
0
А в чем сложность то?
При изменении объекта необходимо следить за целостностью целого объекта. Поэтому хоть ты изменяешь одно поле, хоть весь объект целиком, механизму конкурентных изменений должно быть все-равно.
Допустим, у нас optimistic concurrency. В обоих случаях это будет ровно одна проверка одного поля объекта. И, конечно, это поле нужно в XML варианте, хранить не в самом XML (чтобы его чтение было дешево).
Или имелось ввиду, что при XML потребуется больший объем трафика при небольших изменениях?
При изменении объекта необходимо следить за целостностью целого объекта. Поэтому хоть ты изменяешь одно поле, хоть весь объект целиком, механизму конкурентных изменений должно быть все-равно.
Допустим, у нас optimistic concurrency. В обоих случаях это будет ровно одна проверка одного поля объекта. И, конечно, это поле нужно в XML варианте, хранить не в самом XML (чтобы его чтение было дешево).
Или имелось ввиду, что при XML потребуется больший объем трафика при небольших изменениях?
0
Поскольку первые 4 абзаца у вас состоят из ИМХО и эмоций, разрешите спростить так же:
«Ну почему из трёх вариантов EAV, NoSQL, XML. Вы выбрали самый неподходящий и отстойный. Да ещё и пример привели который решается проще на SQL.»
«Ну почему из трёх вариантов EAV, NoSQL, XML. Вы выбрали самый неподходящий и отстойный. Да ещё и пример привели который решается проще на SQL.»
+14
Эмоции присутствуют, не скрываю, праздники все таки…
На sql проще, само собой, но только когда заранее известна структура данных и заранее можно определить и продумать запросы к ней. Я же описывал ситуацию обратную, когда структура заранее не определена и периодически изменяется.
На sql проще, само собой, но только когда заранее известна структура данных и заранее можно определить и продумать запросы к ней. Я же описывал ситуацию обратную, когда структура заранее не определена и периодически изменяется.
0
В выборе архитектуры хранения очень важны детали. Собственно поэтому в РСУБД применяются такие противоестевтвенные для неё вещи как например денормализация и хинты. А вы не привели никаких подробностей про динамическую часть схемы. И все «минусы» более вменяемых решений выглядят в такой ситуации не просто надуманными, а фиктивными.
Про хранение в XML всех полей записи вы найдёте не меньше негатива.
Джойны там не всегда нужны. А язык запросов как правило там не на стороне сервера а на стороне приложения (хоть и выполняются они и на сервере тоже)
Учитывая динамическую природу у гипотетического примера — её необходимость в классическом смысле под сомнением.
Согласен, что это массово не решённая проблема.
Вы сильно отстали от жизни, это есть, но опять же, не везде.
И без деталей примера вообще не понятно можно было ли обойтись одним SQL.
«EAV. Вызывает у меня стойкую неприязнь, да и сказано и написано об этом было очень много всего негативного (Кайт, Фаулер, Карвин, Горман). Главный минус в том, что при написании запросов приходится оперировать уже не реальными сущностями («Сотрудник», «Дом», «Клиент», то для чего и предназначен SQL), а объектами, орагнизованными на более низком уровне (извините за сумбур). Поэтому это был самый не желательный вариант.»
Про хранение в XML всех полей записи вы найдёте не меньше негатива.
"— Бедный язык запросов (ИМХО) + отсутствие джойнов;"
Джойны там не всегда нужны. А язык запросов как правило там не на стороне сервера а на стороне приложения (хоть и выполняются они и на сервере тоже)
"— Отсутствие схем (хорошая статья недавно была на эту тему "
Учитывая динамическую природу у гипотетического примера — её необходимость в классическом смысле под сомнением.
"— Отсутствие встроенной поддержки ссылочной целостности;"
Согласен, что это массово не решённая проблема.
"— Отсутствие прибамбасов в виде хранимых процедур/функций, триггеров, представлений и многого другого."
Вы сильно отстали от жизни, это есть, но опять же, не везде.
"— В моем приложении помимо данных с гибкой(изменяемой) структурой также необходимо хранить обычные статические данные — таблица пользователей, посещений, сотрудников и т.д. Работать с которыми (опять же имхо) гораздо проще и (самое главное) надежнее в обычной реляционной базе (та же самая ссылочная целостность и пр.)."
И без деталей примера вообще не понятно можно было ли обойтись одним SQL.
+2
Согласен со всеми пунктами. Однако целью моей статьи было показать один из возможных вариантов решения популярной проблемы, саму идею, и небольшой пример использования. Вопрос об использовании данного способа для какой либо конкретной задачи остается открытым, никакой пропаганды нет. Однако для своей задачи я (пока) остановился именно на нем. Описание ее (задачи) целью статьи не являлось, но, если это будет интересно, могу описать ее и причины выбора данного подхода.
+2
О решаемой задаче в кратце.
Сущности (за исключением системных) создаются полностью пользователем (через пользовательский интерфейс), т.е. ядро системы ничего не знает (и не может знать) о них. Далее пользователь должен иметь возможность работать со своими сущностями, выбирать данные из них (выборки могут быть любой сложности, любой степени вложенности и т.д.). Для этого используется QBE, который автоматически преобразуется к обычному sql-запросу, так же остается возможность (для продвинутых пользователей) составлять запросы самостоятельно (для сложных, нетривиальных выборок) на стандартном, хорошо известном многим языке SQL.
При этом пользователь в любом случае (даже при ручном написании запросов) работает со своими логическими объектами, тонкости технической реализации (насколько это возможно) остаются для него скрытыми (чего не скажешь о EAV).
Сущности (за исключением системных) создаются полностью пользователем (через пользовательский интерфейс), т.е. ядро системы ничего не знает (и не может знать) о них. Далее пользователь должен иметь возможность работать со своими сущностями, выбирать данные из них (выборки могут быть любой сложности, любой степени вложенности и т.д.). Для этого используется QBE, который автоматически преобразуется к обычному sql-запросу, так же остается возможность (для продвинутых пользователей) составлять запросы самостоятельно (для сложных, нетривиальных выборок) на стандартном, хорошо известном многим языке SQL.
При этом пользователь в любом случае (даже при ручном написании запросов) работает со своими логическими объектами, тонкости технической реализации (насколько это возможно) остаются для него скрытыми (чего не скажешь о EAV).
0
что мешает при этом создать tablespace, внутри которого создавать просто таблицы?
+2
Создание таблицы в РСУБД это дорогое действие, и совершать его при каждом неосторожном действии пользователя, по любому поводу — думаю не самое лучшее решение (хотя такой вариант я тоже рассматривал).
Так же при малейшем изменении структуры таблицы(таблиц) придется изменять все пользовательские таблицы, потеряется необходимая гибкость.
Так же при малейшем изменении структуры таблицы(таблиц) придется изменять все пользовательские таблицы, потеряется необходимая гибкость.
0
а чем плох EAV?
Простая реляционная структура типа goods<-parameters->categories. Запросы вполне наглядные, будут выглядеть примерно так:
т.е. выбрать иды товаров с ценой от 100 до 200 и цветом «Поносный» либо «Жёлтый». Компактные запросы вполне поддающиеся оптимизации и разграничению прав на элементы справочника параметров. И просто и работает быстро.
Простая реляционная структура типа goods<-parameters->categories. Запросы вполне наглядные, будут выглядеть примерно так:
select price.goods_id from parameters price join categories priceCategory on priceCategory.id=price.category_id and priceCategory.name="Цена" and price.numericValue>100.0 and price.numericValue<200.0 join parameters color join categories colorCategory on colorCategory.id=color.category_id and colorCategory.name="Цвет" and (color.stringValue="Поносный" or color.stringValue="Жёлтый")
т.е. выбрать иды товаров с ценой от 100 до 200 и цветом «Поносный» либо «Жёлтый». Компактные запросы вполне поддающиеся оптимизации и разграничению прав на элементы справочника параметров. И просто и работает быстро.
+2
Проблемы начнутся, когда нужно будет организовать поиск не по всем товарам, а только по конкретным, например среди всех чайников и самоваров и когда сложность запроса немного увеличится. Тогда в ход пойдут айдишники (т.к. в боле менее сложный запрос достаточно накладно все время приджойнивать таблицы с названиями классов и типами параметров (в Вашем случае categories)), а для удобства можно будет держать в голове, что 493832 — это силикатный кипич, а 2345638 — детское питание.
Так же такую структуру сложно проиндексировать, частенько приходится делать мат представления для того или иного конкретного участка (в тех базах где они есть конечно), но от этого беспорядок только увеличивается.
Так же такую структуру сложно проиндексировать, частенько приходится делать мат представления для того или иного конкретного участка (в тех базах где они есть конечно), но от этого беспорядок только увеличивается.
0
нормально всё будет. Добавится ещё условие и всё
select price.goods_id from parameters price join categories priceCategory on priceCategory.id=price.category_id and priceCategory.name="Цена" and price.numericValue>100.0 and price.numericValue<200.0 join parameters color join categories colorCategory on colorCategory.id=color.category_id and colorCategory.name="Цвет" and (color.stringValue="Поносный" or color.stringValue="Жёлтый") join parameters kind join categories kindCategory on kindCategory.id=kind.category_id and kindCategory.name="Изделие" and (kind.stringValue="Чайник" or kind.stringValue="Самовар")
-1
Запросы EAV имеют свойства увеличиваться от сложности задачи гораздо быстрее, чем обычные реляционные.
Вот аналог с применением xml:
Вот аналог с применением xml:
select *
from objects C
where ((xpath('/Изделие/Наименование/text()', O.body))[1]::text::int in ('Чайник', 'Самовар')
and ((xpath('/Изделие/Цвет/text()', O.body))[1]::text::int in ('Желтый', 'Поносный')
and ((xpath('/Изделие/Цена/text()', O.body))[1]::text::int between 100.0 and 200.0;
+1
ну и в чём разница? Только в том что SQL-сервер выполнит запрос мгновенно а все известные мне XML-движки дадут огромный провал в производительности.
+2
16 строчек против 5 плюс абсолютная нечитаемость, и это на элементарном запросе.
К EAV невозможно применить нормальной индексации, при среднем и большом количестве записей «мгновенно» не получится.
К EAV невозможно применить нормальной индексации, при среднем и большом количестве записей «мгновенно» не получится.
0
На softwaremaniacs проскакивало, что если postgresql и нужен EAV, то надо глядеть в сторону hstore www.postgresql.org/docs/9.2/interactive/hstore.html
+1
В-нулевых, для EAV можно и нужно написать хороший ORM, который будет вас абстрагировать от низкоуровневых объектов.
Во-первых, для производительности нужно грамотно настроить индексы и саму db а так же можно делать view's (в оракле) или аналоги в других db.
Во-вторых, три таблицы это самый минимум, на самом деле для удобства использования их нужно иметь несколько десятков.
В-третьих, для очень сложной enterprise-системы вы ничего гибче не придумаете. Не зря, например Magento, на EAV работает.
Моя компания делает продукт, для которого данные хранятся в EAV, спрашивайте вопросы, постараюсь ответить по мере знаний (я не пишу ядро и очень многих тонкостей не знаю) и соблюдения NDA.
Во-первых, для производительности нужно грамотно настроить индексы и саму db а так же можно делать view's (в оракле) или аналоги в других db.
Во-вторых, три таблицы это самый минимум, на самом деле для удобства использования их нужно иметь несколько десятков.
В-третьих, для очень сложной enterprise-системы вы ничего гибче не придумаете. Не зря, например Magento, на EAV работает.
Моя компания делает продукт, для которого данные хранятся в EAV, спрашивайте вопросы, постараюсь ответить по мере знаний (я не пишу ядро и очень многих тонкостей не знаю) и соблюдения NDA.
+1
а есть что-то нетривиальное? расскажите.
0
В-нулевых, для EAV можно и нужно написать хороший ORM, который будет вас абстрагировать от низкоуровневых объектов.
EAV нужен там, где не достаточно ORM: хранение неопределенного заранее (или постоянно изменяющегося) набора сущностей и аттрибутов.
Если же вы можете заранее построить классы для Ваших сущностей (на основе ORM), то почему бы не использовать обычную реляционку.
Во-первых, для производительности нужно грамотно настроить индексы и саму db а так же можно делать view's (в оракле) или аналоги в других db.
Хотел бы посмотреть как строится индексы для EAV-модели.
Насчет вьюх (и мат вьюх) согласен, т.к. это остается единственным способом хоть как то управлять производительностью и читаемостью запросов. Получется, что вместо таблиц приходится создавать представления.
Не зря, например Magento, на EAV работает.
И поэтому, начиная со 2-й версии, от него избавляются:
dimitrigatowski.com/2011/06/19/magento-2-preview/
+1
Я всем рекомендую расширение hstore (http://blog.evtuhovich.ru/blog/2012/01/23/hstore/). За счет его введения устраняется один из основных недостатков реляционных баз данных.
Автору. Не морочьте голову себе и людям.
Автору. Не морочьте голову себе и людям.
+1
Не так давно решали аналогичную задачу, с некоторыми отличиями — динамическая схема нужна только для части колонок, и важна производительность на довольно сложных выборках (много критериев фильтрации + сортировка).
EAV был отброшен как непрактичный (и вероятно ещё и очень медленный). XML и hstore как слишком медленные и требующие много памяти для хранения. Остановились на JSON, накидали функции для его поддержки на perl, а позднее на c.
Если интересно могу написать пост об этом.
EAV был отброшен как непрактичный (и вероятно ещё и очень медленный). XML и hstore как слишком медленные и требующие много памяти для хранения. Остановились на JSON, накидали функции для его поддержки на perl, а позднее на c.
Если интересно могу написать пост об этом.
0
+1 за написание поста.
0
Интересно уточнить чем ваше решение отличается от той же mongodb?
-1
Вопрос не мне (так что извиняюсь), но как минимум, поддержка транзакций и нормальных sql-запросов.
0
Основная причина — для наших задач хороши реляционные бд: транзакции, ссылки на другие таблицы, нецелесообразность переноса всех остальных данных приложения, готовая, заточенная инфраструктура — ORM, кеширование, репликация и партицирование. Выборки по большому количеству непредсказуемых критериев, т.е. то, для чего старые добрые реляционные дб хороши.
Так что добавлять новую технологию в свой стек особого резона не было.
Так что добавлять новую технологию в свой стек особого резона не было.
0
Прошу прощения, невнимательно прочитал вопрос и ответил на «почему вы не использовали MongoDB».
А отличается наше решение тем, что мы продолжаем использовать PostgreSQL со всеми его фишками и наработками со стороны приложения, и тем, что не надо ничего мигрировать, кроме нескольких таблиц, для которых гибкие схемы и нужны
А отличается наше решение тем, что мы продолжаем использовать PostgreSQL со всеми его фишками и наработками со стороны приложения, и тем, что не надо ничего мигрировать, кроме нескольких таблиц, для которых гибкие схемы и нужны
0
спасибо за ответ. я также +1 за написание Вами поста.
0
а в 9.2 вроде json штатно прикрутили. даже с индексами
0
Индексы там на текущий момент только через подключаемый v8/python/perl/etc
Нативно только валидация json и row2json
wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.2#JSON_datatype
Нативно только валидация json и row2json
wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.2#JSON_datatype
0
— Бедный язык запросов (ИМХО) + отсутствие джойнов;
язык запросов не бедный, просто нужно в нем разобраться, относительно джоинов:
docs.mongodb.org/manual/applications/database-references/
группировка:
docs.mongodb.org/manual/reference/command/group/
согласен, все не так просто как хотелось бы, но это есть!
0
не Нескафе, не Чибо и не Якобс, а Несквик, такой же веселый и свободный, выражаясь аллегорично. Просто большинство тех, кто работал с реляционками пытается применить тот же подход к Mongo, но она принципиально другая, дает больше свободы, которой нужно воспользоваться с умом, в начале от нее кружится голова, а потом понимаешь, что зашел далеко, все плохо, и нет, она тебе не подходит, но дело в том, что просто нужно научиться сначала планировать базу а потом ее реализовывать. Ничто не мешает написать обертку, которая будет проверять целостность данных. Как писалось в другой недавней статье, все мы мыслим схемами, в реляционных субд база хранит эту схему за нас, а в не реляционных ее нужно хранить в голове, ну или реализовать самостоятельно алгоритм ее поддержания.
0
Обертку — можно (это я кстати и пытался сделать, когда начинал с Mongo), но во первых это придется делать самому (и работать это будет наверняка медленне, а в реляционке уже все в коробке), а во вторых к такой базе не подойдешь ни слева ни справа, только из конкретного приложения, малейший порыв даже самого легкого ветра со стороны — и что то пошло не так.
Но это конечно от задачи зависит.
ПС продолжая аллегорию, можно вспомнить, что Несквик это вроде детский напиток…
Но это конечно от задачи зависит.
ПС продолжая аллегорию, можно вспомнить, что Несквик это вроде детский напиток…
-1
Несквик не кофе, их нельзя сравнивать, это все-равно что сравнивать молоток и отвертку, каждый делает свою работу и подходит для конкретного случая.
Про обертку спорно, я лично пишу под php, и пишу так, чтобы ее можно было использовать независимо от конкретного приложения, чтобы если есть монго и обертка использовать их вместе можно было из любого скрипта.
Про обертку спорно, я лично пишу под php, и пишу так, чтобы ее можно было использовать независимо от конкретного приложения, чтобы если есть монго и обертка использовать их вместе можно было из любого скрипта.
+1
Sign up to leave a comment.
Postgre(no)SQL или снова о хранении данных с гибкой структурой